- 常识
- 面向对象和面向过程
- 对象的创建和调用
- 对象在内存中的储存
- 构造方法
- this和super
- 重载和重写
- 方法的重写
- 方法的重载
- 面向对象的三大特征
- 封装
- private关键字
- 测试封装的必要性
- 封装方法
- 继承
- 方法的重写
- 测试继承的使用
- 测试继承里方法的使用
- 测试继承中构造方法的使用
- 测试继承中构造方法的使用
- 测试继承中成员变量的使用
- 多态
- 多态的入门案例
- 多态中各元素的用法
- 向上转型和向下转型
- Static和final
- static静态的
- 静态资源入门案例
- 测试静态方法之间的调用
- final最终的
- final入门案例
- 代码块
- 静态代码块
- 构造代码块
- 局部代码块
- 执行顺序
- 代码块入门案例
- 抽象类
- 抽象方法
- 抽象类入门案例
- 测试抽象类中的构造函数
- 测试抽象类中的资源
- 接口
- 接口的入门案例
- 接口入门案例二
- 测试接口中的构造函数
- 测试接口与类之间的关系
- 接口与类之间的关系总结
- 类与类之间的关系
- 类与接口的关系
- 接口与接口之间的关系
- 抽象类与接口的区别
- 内部类
- 对象的普通创建方式
- 内部类入门案例
- 成员内部类
- 成员内部类被private修饰
- 成员内部类被static修饰
- 局部内部类
- 匿名内部类
- 异常
- 异常的继承结构
- 异常的处理方式
- throws 与 throw 的区别
- 面向对象和面向过程都是一种编程思想
- 面向对象强调的是结果, 作为指挥者, 去指挥对象完成实物的处理就可以了
- 面向过程强调的是过程, 作为执行者, 每一件事务都要亲力亲为
java: 面向对象的语言
C: 面向过程的语言
通常将类和对象配合使用, 想要使用自己创建的类或者使用底层API提供的类, 必须要创建对象来调用这个类和类中的方法
- 方法格式: 修饰词 返回值 方法名 (参数列表) {方法体}
public void call() {
System.out.println("正在打电话");
}
- 创建对象格式: 类名 对象名 = new 类名()
Phone p = new Phone(); - 调用对象的方法: 对象名.方法()
p.call();
p.message();
java把内存分为五大区域, 重点关注栈和堆
- 一般来讲, 局部变量存在栈中, 方法执行完毕内存就被释放
- 对象(new出来的)存在堆中, 对象不再被使用时, 内存才会释放
- 每个堆中的元素都有一个地址值存在栈中
- 对象的属性都有默认值
- TIPS: 栈与队列指的是一种数据的结构
- 栈: 先进后出(FILO – First In Last Out)
- 队列:先进先出(FIFO – First In First Out)
- 格式: 修饰符 类名(){ }
- 与类同名且没有返回值类型的参数
- 每一个类中默认会有一个构造方法, 可以不传参数直接创建这个类的对象, 就是用于创建对象
- 如果这个类提供了其他的构造函数,默认的无参构造会被覆盖掉,所以需要手动提供无参构造
- 构造方法也存在重载的现象:无参构造 含参构造 全参构造【创建对象+属性赋值】
- super
- 代表的是父类对象的引用,我们可以把super看作是Father super = new Father();
- 父类成员变量和子类的变量同名时可以用super.变量名 指定使用父类的变量
- super();表示调用父类的无参构造 super(参数);表示调用父类的对应参数的构造
- this
- this代表的是本类对象的引用,我们可以把this看作是Cat this = new Cat();
- 当本类的成员变量与局部变量同名时,需要使用this.变量名指定本类的成员变量
- this();表示调用本类的无参构造 this(参数);表示调用本类的对应参数的构造
出现在继承中, 如果继承了父类中的一个方法, 但是不想使用这个方法的功能, 可以在子类中重写这个方法
- 返回值类型, 方法名, 参数列表必须与父类中想要重写的方法一致
- 重写方法体里的代码内容
- 重写原则: 两同 两小 一大
- 一大: 子类方法的修饰符范围>=父类方法的修饰符范围–访问控制符
- 两同: 方法名相同,参数列表相同
- 两小:
- 子类返回值类型 <= 父类方法的返回值类型
- 子类方法抛出的异常类型 <= 父类方法抛出的异常类型
注意: 父类方法的返回值类型为void,子类保持一致即可
方法的重载重载出现在同一个类中, 如果想使用不同参数的同一个方法时, 要使用重载
- 返回值, 方法名相同, 参数列表不同
将一个事务的属性和行为,(变量和方法)封装成一个类组件private关键字
通过private关键字修饰后,属性只能在本类中使用,需要对外提供公共的getXxx()与setXxx()
好处:
- 提高安全性
- 提高重用性
package cn.tedu.oop;
public class TestPrivate1 {
public static void main(String[] args) {
//5.创建对象进行测试
User u = new User();
u.name = "西门庆";
System.out.println(u.name);
//需要封装属性,如果不封装的话,就可以直接修改属性的值
//不需要按照我们预先设置好的方式也能操作
//u.money = 1000000;
//System.out.println(u.money);
u.setMoney(109999);
System.out.println(u.queryMoney());
}
}
//1.创建一个用户类User
class User{
//2.定义用户类的属性
public String name;
private double money = 10000;
//3.提供方法1:可以用来查询当前账户的余额
public double queryMoney(){
return money;
}
//4.提供方法2:可以设置当前账户的余额
public void setMoney(double money){
this.money = money;
}
}
封装方法
如果一个方法被private修饰,外界想要调用这个功能,需要在本类中提供一个公共的方法调用这个私有方法 比如封装属性与方法,主要是对资源进行了访问限制,想让外界按照我们提供的方式来使用继承
继承具有传递性, 创建一个类作为父类, 在创建一个类使用extends关键字继承父类, 就可以使用父类中的所有功能, 还可 以扩展自己的功能
- 私有资源会被继承, 但不能使用, 因为不可见
- 构造方法不能被继承, 构造方法要求方法名与类名相同, 所以不能在子类中出现父类名字的构造方法
- java只允许单继承, 一个子类只能继承一个父类, 一个父类可以有多个子类
如果继承了父类中的一个方法, 但是不想使用这个方法的功能, 可以在子类中重写这个方法
- 返回值类型, 方法名, 参数列表必须与父类中想要重写的方法一致
- 重写方法体里的代码内容
- 重写原则: 两同 两小 一大
- 一大: 子类方法的修饰符范围>=父类方法的修饰符范围–访问控制符
- 两同: 方法名相同,参数列表相同
- 两小:
- 子类返回值类型 <= 父类方法的返回值类型
- 子类方法抛出的异常类型 <= 父类方法抛出的异常类型
注意: 父类方法的返回值类型为void,子类保持一致即可
测试继承的使用package cn.tedu.Extend;
public class Extends {
public static void main(String[] args) {
//创建3个类的对象
Animal a = new Animal();
Cat c = new Cat();
MiaoMiao m = new MiaoMiao();
//利用对象调用方法进行测试
a.eat();
c.eat(); //爸爸类可以使用爷爷类的方法
m.eat(); //孙子类可以使用爸爸类继承来的爷爷类的方法
}
}
//爷爷类
class Animal {
// 创建爷爷类的方法
public void eat() {
System.out.println("小动物Animal吃啥都行~");
}
}
//爸爸类,与Animal建立继承关系
class Cat extends Animal{
//定义属性--成员变量
int a = 10; //普通资源
private int b = 100; //私有资源
}
//孙子类,与Cat建立继承关系
class MiaoMiao extends Cat{
//定义孙子独有的方法
public void studyJava() {
System.out.println("正在学Java");
System.out.println(a);
// System.out.println(b);
}
}
测试继承里方法的使用
package cn.tedu.Extend;
public class ExtendsRewriteMethod {
public static void main(String[] args) {
Father3 f3 = new Father3();
Son3 s3 = new Son3();
f3.eat();
//重写后使用的子类重写的功能
s3.eat(); //继承后子类可以使用父类的非私有资源
}
}
class Father3{
public void eat() {
System.out.println("爸爸爱吃饭");
}
public void play() {
System.out.println("爸爸爱放风筝");
}
}
class Son3 extends Father3 {
//拓展功能
public void studyJava() {
System.out.println("我扩展了Java的功能");
}
//重写父类中的eat方法
@Override
public void eat() {
System.out.println("儿子爱吃蔬菜");
}
}
测试继承中构造方法的使用
package cn.tedu.Extend;
public class ExtendsConstructionMethod {
public static void main(String[] args) {
Father2 f2 = new Father2("参数");
Son2 s2 = new Son2();
}
}
class Father2 {
//创建父类的无参构造
public Father2(){
System.out.println("我是Father2的无参构造");
}
public Father2(String s){
System.out.println("我是Father2的"+s);
}
}
class Son2 extends Father2{
//子类无参构造方法
public Son2() {
super("含参构造");
System.out.println("我是son2的无参构造");
}
}
测试继承中构造方法的使用
package cn.tedu.Extend;
public class ExtendsConstructionMethod {
public static void main(String[] args) {
Father2 f2 = new Father2("参数");
Son2 s2 = new Son2();
}
}
class Father2 {
//创建父类的无参构造
public Father2(){
System.out.println("我是Father2的无参构造");
}
public Father2(String s){
System.out.println("我是Father2的"+s);
}
}
class Son2 extends Father2{
//子类无参构造方法
public Son2() {
super("含参构造");
System.out.println("我是son2的无参构造");
}
}
测试继承中成员变量的使用
package cn.tedu.Extend;
public class ExtendsSuper {
public static void main(String[] args) {
Son s = new Son();
s.eat();
}
}
class Father {
//定义父类的成员变量
int count = 1;
int sum = 2;
}
class Son extends Father {
//定义成员变量
int sum = 100;
public void eat() {
//定义局部变量
int sum = 10;
System.out.println(sum); //打印局部变量
System.out.println(this.sum); //打印成员变量
//使用父类的成员变量
System.out.println(count); //使用父类不重名的成员变量
System.out.println(super.sum); //使用父类重名的成员变量
}
}
多态
同一个对象, 不同时刻, 代表的对象不一样, 拥有多种形态 可以把不同的子类对象都当作父类来看,进而屏蔽不同子类对象之间的差异,写出通用的代码,统一调用标准。
多态的前提: 继承+重写
- 父类引用, 指向子类对象
- 编译看左边, 运行看右边
因为引用的父类对象, 在编译的时候只会编译父类里有的资源, 子类自己扩展的功能不会被编译
public class Polymorphism {
public static void main(String[] args) {
Animal a = new Animal();
Cat c = new Cat();
Dog d = new Dog();
a.eat();
c.eat();
d.eat();
// a.play();
c.play();
d.play();
Animal a2 = new Cat();
Animal a3 = new Dog();
a2.eat();
// a2.play();
}
}
class Animal{
public void eat() {
System.out.println("小动物Animal吃啥都行");
}
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("小猫爱吃小鱼干");
}
public void play() {
System.out.println("小猫cat跳的可高了");
}
}
class Dog extends Animal {
@Override
public void eat() {
System.out.println("小狗爱吃肉骨头");
}
public void play() {
System.out.println("小狗Dog跑的老快了");
}
}
多态中各元素的用法
package cn.tedu.polymorphism;
public class Demo2 {
public static void main(String[] args) {
Animal2 a = new Animal2();
Dog2 d = new Dog2();
//多态对象
Animal2 a2 = new Dog2();
d.eat();
d.play();
System.out.println(a2.sum);
a2.eat();
a2.play();
}
}
class Animal2 {
int sum = 10;
public void eat() {
System.out.println("吃啥都行");
}
public static void play() {
System.out.println("玩啥都行");
}
}
class Dog2 extends Animal2{
int sum = 20;
@Override
public void eat() {
System.out.println("小狗爱吃肉包子");
}
public static void play() {
System.out.println("小狗爱打滚");
}
}
- 成员变量:使用的是父类的
- 成员方法:由于存在重写,所以是父类的声明,子类的方法体
- 静态资源:静态资源属于类资源,是谁的,就返回谁的,而多态把自己看作父类类型,所以使用的是父类的
- 父类引用指向子类对象: 向上转型(常用) Parent p = new Child();
- 子类引用指向子类对象: 向下转型 Child c = (Child)p;
- 必须要进行强制转型, 把Parent类型的p转成小类型Child
- 就可以使用子类扩展的功能了
static关键字,可以修饰变量、方法、代码块、内部类,代表是静态的资源
- 静态资源可以通过类名 .直接调用, 因为优先于对象加载, 随着类的加载而加载, 不用创建对象就可以直接通过类名调用
- 静态资源全局被所有对象共享,值只有一份
- 不能与this和super公用, 因为没有对象
- 静态资源只能调用静态资源,非静态资源不做限制,静态与非静态都能使用
package cn.tedu.Static;
public class Static {
public static void main(String[] args) {
System.out.println(Student.name);
Student.study();
//创建对象
Student s = new Student();
System.out.println(s.sno);
System.out.println(s.name);
s.study();
s.name = "金角大王";
System.out.println(s.name);
//7.创建多个对象进行测试
Student s2 = new Student();
System.out.println(s2.name);
System.out.println(Student.name);
s2.name = "银角大王";
System.out.println(s.name);
System.out.println(s2.name);
System.out.println(Student.name);
}
}
class Student {
//定义属性
int sno;//学号
static String name;//姓名
//定义方法
public static void study() {
System.out.println("学Java呢");
}
public void speak() {
System.out.println("爱就大声说出来");
}
}
测试静态方法之间的调用
package cn.tedu.Static;
public class StaticTransfer {
}
class Teacher {
String name;
public void teach() {
System.out.println("正在上课中..");
System.out.println(age);
ready();
}
static int age;
public static void ready() {
System.out.println("正在备课中..");
// System.out.println(name);
// teach();
}
public static void eat() {
System.out.println("正在吃饭中..");
System.out.println(age);
ready();
}
}
final最终的
final关键字, 表示最终的, 用来修饰类 方法 属性
- 修饰类是最终类, 不能被继承, 叶子节点
- 修饰方法代表最终实现, 不能被重写
- 修饰属性是常量, 值不能修改
- 定义常量必须赋值, 否则报错
package cn.tedu.Final;
public class Final {
public static void main(String[] args) {
Son s = new Son();
// s.name = "干饭人"; //会报错,因为常量的值不能被修改
}
}
//测试类被final修饰
//final class Father { }
class Father {
// final public void work() {
// System.out.println("在车间上班..");
// }
public void work() {
System.out.println("在车间上班..");
}
}
class Son extends Father {
final String name = "打工人";
// final int a; 定义常量时必须要同时赋值, 不能先定义再赋值, 不符合语法
//重写父类work方法
@Override
public void work() {
System.out.println("在格子间上班..");
}
}
代码块
静态代码块
- 位置: 类里方法外
- 执行时机: 属于静态资源, 随着类的加载而加载, 优先于对象加载并且只加载一次
- 作用: 用于加载需要第一时间就加载, 并且只加载一次的资源
- 位置: 类里方法外
- 执行时机: 每次创建对象时被触发, 并且优先于构造方法执行
- 作用: 用于提取所有构造方法的共性功能
- 位置: 方法里
- 执行时机: 执行局部代码块所在的方法时才会执行
- 作用: 用于限制变量的作用范围
静态代码块->构造代码块->构造方法(对象创建成功)->局部代码块
代码块入门案例package cn.tedu.Static;
public class StaticBlock {
public static void main(String[] args) {
Person p = new Person();
Person p2 = new Person();
p.play();
}
}
class Person {
//静态代码块
static {
System.out.println("我是静态代码块");
}
//构造代码块
{
System.out.println("我是构造代码块");
}
//构造方法
public Person() {
System.out.println("我是无参构造");
}
//普通方法
public void play() {
System.out.println("我是一个普通方法");
//局部代码块
{
System.out.println("我是局部代码块");
}
}
}
抽象类
abstract关键字定义抽象类和抽象方法
- 如果一个类包含了一个抽象方法, 必须要将这个类定义为抽象类
- 抽象类不能被实例化, 必须通过继承, 在子类实现抽象类里的抽象方法
- 当一个类继承了抽象父类,有两种解决方案:
- 变成抽象子类
- 变成普通子类, 或实现抽象父类中的所有抽象方法
- 抽象类有构造方法, 为了子类实现时使用super()创建对象
- 抽象类中的资源:
- 成员变量
- 成员常量
- 普通方法
- 抽象方法
- 构造方法
被abstract修饰的方法是抽象方法, 抽象方法没有方法体
格式: abstract public void 方法名()
抽象类入门案例package cn.tedu.Abstract;
public class Demo {
public static void main(String[] args) {
// new Phone();
Phone p = new XM();
p.money();
p.call();
}
}
abstract class Phone {
public void call() {
System.out.println("正在打电话..");
}
public void message() {
System.out.println("正在发短信..");
}
//抽象方法
abstract public void money();
abstract public void money2();
}
//abstract class XM extends Phone {
class XM extends Phone {
@Override
public void money() {
System.out.println("实现父类未实现的方法1");
}
@Override
public void money2() {
System.out.println("实现父类未实现的方法2");
}
}
测试抽象类中的构造函数
package cn.tedu.Abstract;
public class Demo2 {
public static void main(String[] args) {
Pig p = new Pig();
}
}
abstract class Animal {
public Animal() {
System.out.println("我是Animal类中的构造方法");
}
}
class Pig extends Animal{
public Pig() {
super();
System.out.println("我是Pig中的无参构造");
}
}
测试抽象类中的资源
package cn.tedu.Abstract;
public class Demo3 {
}
abstract class Fruit {
int sum = 100; //成员变量
final String name = "XHR"; //成员常量
public void clean() {
System.out.println("普通方法");
}
abstract public void grow(); //抽象方法
abstract public void clean2();
}
class Banana extends Fruit {
@Override
public void grow() {
System.out.println("一串香蕉老沉了");
}
@Override
public void clean2() {
System.out.println("香蕉不用洗");
}
}
接口
可以当做是一个特殊的抽象类 interface关键字来定义接口 implements关键字与接口建立实现关系, 实现方法与抽象类一样, 必须实现接口中的所有抽象方法
- 接口中全部为抽象方法,没有构造方法
- 一般创建的都是接口实现类的对象, 创建多态对象也可以(不推荐)
- 接口实现类构造方法中的第一行super()调用的是默认继承的顶级父类object中的无参构造
- 接口中没有成员变量, 而是静态常量, 会默认拼接static和final
- 静态的表现: 可以通过接口名直接调用
- 常量的表现: 值不可以被修改, 需要定义的同时赋值
- 创建接口的测试
package cn.tedu.Inter;
public interface Inter {
// public void eat(){}
abstract public void eat();
abstract public void play();
}
- 创建接口的实现类
package cn.tedu.Inter;
//abstract public class InterImpl implements Inter{
public class InterImpl implements Inter{
@Override
public void eat() {
System.out.println("吃火锅");
}
@Override
public void play() {
System.out.println("玩代码");
}
}
- 创建接口实现类对象
package cn.tedu.Inter;
public class InterTest {
public static void main(String[] args) {
Inter i = new InterImpl(); //多态对象
i.eat();
i.play();
InterImpl i2 = new InterImpl(); //接口实现类对象
i.eat();
i.play();
}
}
接口入门案例二
package cn.tedu.Inter2;
public class DesignTeacher {
public static void main(String[] args) {
CGBTeacher c = new CGBTeacher();
ACTTeacher a = new ACTTeacher();
c.ready();
c.teach();
a.ready();
a.teach();
}
}
//1. 创建Teacher接口-- 提取共性, 形成抽象层, 体现接口, 接口定义的是规则
interface Teacher {
//2. 定义接口中的抽象方法
void ready();
void teach();
}
//3. 创建实现类
class CGBTeacher implements Teacher {
@Override
public void ready() {
System.out.println("正在备课Java");
}
@Override
public void teach() {
System.out.println("正在授课Java");
}
}
class ACTTeacher implements Teacher {
@Override
public void ready() {
System.out.println("正在备课高手加薪");
}
@Override
public void teach() {
System.out.println("正在授课高手加薪");
}
}
测试接口中的构造函数
package cn.tedu.Inter2;
public class TestUserInter {
public static void main(String[] args) {
Inter2Impl i = new Inter2Impl();
System.out.println(Inter2.age);
}
}
interface Inter2 {
// public Inter2(){}
int age = 10;
void eat();
}
class Inter2Impl implements Inter2 {
public Inter2Impl() {
System.out.println("我是实现类的无参构造");
}
@Override
public void eat() {
System.out.println("吃吃吃");
}
}
测试接口与类之间的关系
package cn.tedu.Inter2;
public class Relation {
}
interface Inter1 {
void save(); //保存方法
void find(); //查询方法
}
interface Inter22 {
void update(); //更新方法
void delete(); //删除方法
}
interface Inter3 extends Inter1,Inter22 {
}
//class Inter3Impl implements Inter3 {
class Inter3Impl implements Inter1,Inter22 {
@Override
public void save() {
System.out.println("正在保存");
}
@Override
public void find() {
System.out.println("正在查询");
}
@Override
public void update() {
System.out.println("正在修改");
}
@Override
public void delete() {
System.out.println("正在删除");
}
}
接口与类之间的关系总结
类与类之间的关系
● 继承关系,只支持单继承
○ 比如:class A extends B,A是子类,B是父类,子类具备父类的所有功能
- 实现关系,既可以单实现,也可以多实现
- 比如:class A implements Inter1{}
- 比如:class A implements Inter2,Inter3{}
- A是实现类,Inter1,Inter2,Inter3是被实现的接口
- 注意1:实现类去实现接口必须实现接口中的所有抽象方法,如果有任何一个没有实现,就得声明成抽象子类
- 注意2:创建实现类对象时,一般使用实现类对象,而不是多态对象,因为效果一样
- 继承关系,既可以单继承,也可以多继承
- 比如:interface A extends Inter1{}
- 比如:interface A2 extends Inter2,Inter3{}
- A,A2是子接口,Inter1,Inter2,Inter3是被继承的父接口
- 注意: 接口A2的实现类需要实现接口A2继承自Inter2和Inter3的所有抽象方法
- 抽象类
- 抽象类是一个特殊的类,使用class定义,特殊在这个类中可以定义没有方法体的方法(抽象方法)
- 抽象类中有构造方法,为了给子类创建对象时调用
- 抽象类只能单继承
- 抽象类不可以实例化/创建对象
- 抽象类可以定义普通的成员变量
- 抽象类是后天重构的结果
- 接口
- 接口可以理解成一个特殊的抽象类,用interface定义, 接口中所有的方法都是抽象方法,接口不是类
- 接口中没有构造方法的,子类调用的是父类的构造方法
- 接口可以多继承
- 接口不可以实例化/创建对象
- 接口只能定义静态常量
- 接口是先天设计的结果
- 可以把内部类看作是外部类的一个特殊的资源
- 内部类可以直接使用外部类的所有资源,包括私有资源
- 外部类如果想要使用内部类的资源,需要创建内部类的对象才能使用
- 在成员位置的内部类是成员内部类
- 在局部位置的内部类是局部内部类
如果一个类存在的意义就是为指定的另一个类,可以把这个类放入另一个类的内部。
就是把类定义在类的内部的情况就可以形成内部类的形式。
A类中又定义了B类,B类就是内部类,B类可以当做A类的一个成员看待:
外部类名.内部类名 对象名 = 外部类对象.内部类对象 Outer.Inner oi = new Outer().new Inner();内部类入门案例
package cn.tedu.innerclass;
public class TestInner1 {
public static void main(String[] args) {
//3.创建内部类对象,使用内部类的资源
Outer.Inner oi = new Outer().new Inner();
oi.delete();
System.out.println(oi.sum);
//4.调用外部类的方法--这样是创建了一个外部类的匿名对象,只使用一次
new Outer().find();
}
}
//1.创建外部类 Outer
class Outer{
//1.1创建外部类的成员变量
String name;
private int age;
//1.2创建外部类的成员方法
public void find(){
System.out.println("Outer...find()");
//6.测试外部类如何使用内部类的资源
//System.out.println(sum);--不能直接使用内部类的属性
//delete();--不能直接调用内部类的方法
Inner in = new Inner();
System.out.println(in.sum);
in.delete();
}
//2.创建内部类Inner--类的特殊成员
class Inner{
//2.1定义内部类的成员变量
int sum = 10;
//2.2定义内部类的成员方法
public void delete(){
System.out.println("Inner...delete()");
//5.测试内部类是否可以使用外部类的资源
System.out.println(name);
System.out.println(age);
//find();
}
}
}
成员内部类
类里方法外
成员内部类被private修饰- 被私有化的内部类在main()中是没有办法直接创建其对象的
- 可以在私有内部类所处的外部类中,创建一个公共的方法供外界调用,这个方法用来返回创建好的私有内部类对象
package cn.tedu.innerclass;
public class TestInner2 {
public static void main(String[] args) {
//4.创建内部类Inner2对象进行访问
//Outer2.Inner2 oi = new Outer2().new Inner2();
//oi.eat();
//7.创建外部类对象,间接访问私有内部类资源
new Outer2().getInner2Eat();
}
}
//1.创建外部类Outer2
class Outer2{
//6.提供外部类公共的方法,在方法内部创建Inner2内部类对象,调用内部类方法
public void getInner2Eat() {
Inner2 in = new Inner2();//外部类可以访问内部类的私有成员
in.eat();
}
//2.1创建成员内部类Inner2
//5.成员内部类,被private修饰私有化,无法被外界访问
private class Inner2{
//3.创建内部类的普通成员方法
public void eat() {
System.out.println("我是Inner2的eat()");
}
}
}
成员内部类被static修饰
- 静态内部类可以不创建外部类对象,直接创建静态内部类对象,格式:Outer3.Inner3 oi = new Outer3.Inner3();
- 如果静态内部类中还有静态方法,那么我们可以不创建对象
- 直接通过链式加载的方式调用:Outer3.Inner3.show2();//表示通过外部类名直接找到静态内部类,再找到静态方法
package cn.tedu.innerclass;
public class TestInner3 {
public static void main(String[] args) {
//4.创建内部类对象访问show()
//方式一:按照之前的方式,创建内部类对象调用show()
//Outer3.Inner3 oi = new Outer3().new Inner3();
//oi.show();
//方式二:创建匿名内部类对象访问show()
//new Outer3().new Inner3().show();
//6.用static修饰内部类以后,上面的创建语句报错,注释掉
//通过外部类的类名创建内部类对象
Outer3.Inner3 oi = new Outer3.Inner3();
oi.show();
//7.匿名的内部类对象调用show()
new Outer3.Inner3().show();
//9.访问静态内部类中的静态资源--链式加载
Outer3.Inner3.show2();
}
}
//1.创建外部类Outer3
class Outer3{
//2.创建成员内部类Inner3
//5.内部类被static修饰—并不常用!浪费内存!
static class Inner3{
//3.定义成员内部类中普通的成员方法
public void show() {
System.out.println("我是Inner3类的show()");
}
//8.定义成员内部类的静态成员方法
static public void show2() {
System.out.println("我是Inner3的show2()");
}
}
}
局部内部类
- 位置:方法里
- 直接创建外部类对象,调用局部内部类所处的方法,并不会触发局部内部类的功能
- 需要在外部类中创建局部内部类的对象并且进行调用局部内部类的功能,才能触发内部类的功能
package cn.tedu.innerclass;
public class TestInner4 {
public static void main(String[] args) {
//5.创建外部类对象调用show()
//7.当在外部类show()中创建局部内部类对象并且进行功能调用后,内部类的功能才能被调用
new Outer4().show();
}
}
//1.创建外部类Outer4
class Outer4{
//2.创建外部类的成员方法
public void show() {
//3.创建局部内部类Inner4—不太常用!!!
class Inner4{
//4.创建局部内部类的普通属性与方法
String name;
int age;
public void eat() {
System.out.println("我是Inner4的eat()");
}
}
//6.在show()里创建内部类对象
Inner4 in = new Inner4();
in.eat();
System.out.println(in.name);
System.out.println(in.age);
}
}
匿名内部类
- 位置:可运行代码中,比如 main()中
- 匿名内部类通常与匿名对象【没有名字的对象】一起使用
- 格式:new Inter1(){ 我这个大括号其实是一个匿名内部类,我来实现方法 }.eat();
- 如果只是想使用一次接口/抽象类的某个功能,可以使用匿名内部类
- 匿名内部类+匿名对象的功能:创建实现类+实现方法+方法功能的一次调用【功能三合一】
package cn.tedu.innerclass;
public class TestInner5 {
public static void main(String[] args) {
//传统方式:创建接口的实现类+实现类实现接口中的抽象方法+创建实现类对象+通过对象调用方法
//3.创建接口一对应的匿名对象与匿名内部类,并调用实现了的方法save()
new Inter1(){
@Override
public void save() {
System.out.println("save()...");
}
@Override
public void get() { }
}.save();
//5.创建抽象类对应的匿名对象与匿名内部类
new Inter2(){
@Override
public void drink() {
System.out.println("一人饮酒醉");
}
}.drink();
//7.调用普通类的功能怎么调用?创建匿名对象直接调用
new Inter3().powerUp();
new Inter3().powerUp();//new了2次,所以是两个匿名对象
Inter3 in = new Inter3();
in.study();
in.study();
in.study();
in.study();
in.study();
in.study();
}
}
//1.创建接口
interface Inter1{
//2.定义接口中的抽象方法
void save();
void get();
}
//4.创建抽象类
abstract class Inter2{
public void play(){
System.out.println("Inter2...play()");
}
abstract public void drink();
}
//6.创建普通类
class Inter3{
public void study(){
System.out.println("什么都阻挡不了我想学习赚钱的决心");
}
public void powerUp(){
System.out.println("我们会越来越强的!");
}
}
异常
异常的继承结构
异常的处理方式
捕获方式:
抛出方式:
对于不想现在处理或者处理不了的异常可以选择向上抛出
在方法上设置异常的抛出管道: throws 异常类型
例如:void method1 throws Exception1,Exception2,Exception3{ }
throws 与 throw 的区别throws :
- 用在方法声明处,其后跟着的是异常类的名字
- 表示此方法会抛出异常,需要由本方法的调用者来处理这些异常
- 但是注意:这只是一种可能性,异常不一定会发生
throw :
- 用在方法的内部,其后跟着的是异常对象的名字
- 表示此处抛出异常,由方法体内的语句处理
- 注意:执行throw一定抛出了某种异常



