Java_Day10 多态+内部类
.01
.02
多态
猫 x = new 猫();
动物 x = new 猫();
一个对象对应着不同类型。
多态在代码中的体现:父类或者接口的引用指向了其子类的对象。
.03
多态的好处:提高了代码的扩展性,前期定义的代码可以使用后期的内容。
第100行(animal a)使代码简单,其下面的两个method就可以省略 ,这是多态性的使用。
.04动态的弊端
前期定义的内容 不能调用后期子类中的特有内容。
84行会出现错误,因为animal中没有catchMouse的方法
多态的前提:1:必须要有关系,继承,实现。
2:要有覆盖。
.05转型
猫提升为动物 只能使用动物类中的方法,如果做eat这个动作,调用的是子类猫中的吃,因为子类中与父类有相同的eat方法,而子类覆盖了父类的eat方法(覆盖只发生在函数上,不发生在变量上)
专业讲:向上转型。将子类型隐藏。就不用使用子类的特有方法。(除非父类子类有同样的方法,子类会覆盖父类,执行子类中的方法)
Animal a强制转换为(cat) 即向下转型
但是a创建时必须是cat型 如果是animal a = new animal()或者new成其他dog型等,则a不能强转成cat型
错误例子:
Classcastexception 类转换错误
对于转型,自始至终都是子类对象在做着类型的变化。
.06转型
.07多态类型判断
Main函数中将dog向上转为了animal
调用method时,如果用a.catchMouse()语句会出现错误
因为dog不是cat,没有catchmouse这个方法
所以必须进行判断
If(a instanceof Cat) 如果对象a传进来之前本身是cat则进行判断,如果是 进入if语句
才能再调用cat中的catchmouse方法
instanceof:用于判断对象的具体类型。只能用于引用数据类型判断
通常在向下转型前用于健壮性的判断。
.08多态_成员变量
多态时:
成员的特点:
1.成员的变量。
a) 编译时:参考引用型变量所属的类中的是否有调用的成员变量,有,编译通过,没有,编译失败。
b) 运行时:参考引用型变量所属的类中的是否有调用的成员变量,并运行该所属类中的成员变量。
c) 编译和运行都参考等号的左边。
解释c:(面试中会考察,实际应用中很少出现这种情况,作为了解)
运行26行,输出3,
看等号左边,23行定义是:
Fu f = ,是父类中的 所以Num输出的是Fu中的Num 3
如果23行等号左边是是:Zi f = ,则输出4
另外:如果等号左边是Zi f =,而子类中没有定义成员变量即://int num =4;
那么f.num会调用父类的num,如果父类中的Num也没有,那么就会出现a)编译失败
.09多态_成员函数
2.成员函数(这是非静态,依靠对象有关)。
编译时:参考引用型变量所属的类中的是否有调用的函数。有,编译通过,没有,编译失败。
运行时:参考的是对象所属的类中是否有调用的函数。
简单说:编译看左边,运行看右边。
因为成员函数存在覆盖特性。
第28行中的f.show输出的是zi show也就是调用子类的show,其实是应该先用父类的show但是子类父类都有相同的方法,子类覆盖了父类的show,所以执行输出的是zi show,但是如果父类中没有show()方法,则编译失败。
编译的时候看的等号左边。Fu f = ,如果父类中没有show,那么编译失败。
如果子类没有show方法,则用父类的show
Fu f = new Zi();
等号左边:引用型变量 等号右边:对象所属类
.10多态_静态函数
静态函数(静态,跟类有关,一创建就有所属了,叫做静态型绑定,跟对象无关)
编译时:参考引用型变量所属的类中的是否有调用的静态方法。
运行时:参考引用型变量所属的类中的是否有调用的静态方法。
简单说,编译和运行都看左边。
其实对于静态方法,是不需要对象的。直接用类名调用即可。
.11内部类
内部类访问特点:
1.内部类可以直接访问外部类中的成员。
2.外部类要访问内部类,必须建立内部类的对象。
一般用于类的设计。
分析事物时,发现该事物描述中还有事物,而且这个事物还在访问被描述事物的内容,这是就是还有的事物定义成内部类来描述。
.12内部类——修饰符(不常见)
Class outer
{
Class inner
}
Outer.inner a = new outer().new inner();
Class outer
{
Static Class inner//如果是静态内部类,相当于外部类
}
Outer.inner in = new outer.inter();
如果内部类都是静态的,成员是静态的。
Outer.inner.方法();
当内部类如果内部类定义了静态成员,该内部类必须被静态修饰
.13内部类-细节
11行如果是system.out.println(num);输出5
如果是system.out.println(this.num);输出4
如果是system.out.println(outer.this.num);输出3
为什么内部类能直接访问外部类的成员呢?
因为内部类持有了父类的引用 外部类名.this
.14局部内部类
内部类可以放在局部位置上。可以放到for循环里面。
如果内部类在局部位置method里面,new内部类对象的时候,要跟内部类在同一局域内,并且必须在内部类的下面,不能在内部类的上面。
第12行,必须定义成final
原理:内部类在局部位置上,只能访问局部中被final修饰的局部变量。
.15匿名内部类
内部类的简写模式
必须有前提:内部类必须继承或者实现一个外部类或者接口。
匿名内部类:其实就是一个匿名子类对象。
34-40就是匿名内部类 代替了23-29行内容
格式:new 父类or接口(){子类内容}
.16匿名内部类-应用
通常的使用场景之一:
当函数参数是接口类型时,而且接口中的方法不超过三个。
可以用匿名内部类作为实际参数进行传递
.17匿名内部类—细节
.18对象的初始化过程
New对象时,到子类的构造对象中,第19行,有个隐藏的super(super只默认存在于子类构造函数中),再运行到父类的无参构造函数,父类无参构造函数中有一个show()方法,这时因为子类也有show()方法 会覆盖父类show ,所以执行子类中的show,此时num=9还没有运行,说明new对象时,先默认初始化0,再进行构造函数初始化的super内容,之后,回到子类的无参构造函数,再进行第17行的显示初始化,再执行20行。
Super()是直接转到父类的无参构造函数?是的
New Zi();
1.子类默认初始化0
2.子类无参构造函数中的super->父类的无参构造函数
3.父类无参构造函数super(到object,但是无作用)
4. 第11行 显示初始化num=9;
5. 第12行 打印Fu
6. 第13行show但是子类有show覆盖父类的show输出32行的zi show
(注意:虽然父类显示初始化num=9 ,但是回到子类的show num还是0)
7. 第27行显示初始化num=8
8. 构造代码初始化 输出22行Zi
9. 第28行,再次调用子类show输出zi show...8
来源:CSDN
作者:ACMer_Shadow
链接:https://blog.csdn.net/qq_24653023/article/details/51755662