多态篇回顾
1:理解引用变量的编译期类型和运行期类型
编译器类型:编译时使用类型
运行时类型:运行时实际执行的类型
多态:编译时类型和运行时类型不一致
Object a = new Dog(); //编译类型为Object 运行时类型为Dog
2:向上转型:同一个类型方法出现了不同行为
class Dog{metnod(){sop("dog")}}
class Cat{metnod(){sop("cat")}}
Object dog=new Dog();
Object cat=new Cat();
dog.metnod()和cat.method()出现的行为不同
//同为Object类型,但是执行的时不同的行为,因为具有继承关系的子类,运行时实际调用为子类方法
//运行时调用变量方法是总是出现子类行为,而不是父类方法的行为特征
3:多态
//子类对象指向父类引用
//同一类型调用同一方法可能出现不同的行为特征,
多态体现在成员方法,成员变量不存在多态性
4:引用类型由于多态特性,编译期调用实际执行对象的方法可能会报错
编译期检查的时编译类型,运行时访问的时实际类型
编译期只能调用编译类型存在的方法,否则报错
5:强制转换:向上转型、向下转型
基本类型的强转:只能转换数值类型,int double float.. 不能数值和布尔类型转换
引用类型强转:必须具有extends关系的类或接口进行强转
向上转型默认实现
向下转型必须强制转换: 是否可以比较看的是编译类型,真正比较看的是运行类型
5.1:向下转型可能出现错误:编译时有extends关系,运行时无extends关系
eg: Object obj = new Integer();
//编译期str/obj具有继承关系,运行时,obj类型不再是Object类型,而是Integer类型,obj和str不再具有继承关系
String str = (String)obj; //ClassCastException 类转换异常
5.2:instanceof避免向下转型的错误情况
if(obj instance String){//先判断obj是不是String类型在进行转换
String str = (String)obj;
}
5.2.1:instanceof
前一个一般为引用变量,后一个为类或接口,
判断前是不是后类的实例 或者后类的子类或实现类的实例
返回 true/false
前后编译类型应为同类或者继承关系的类
继承与组合
1:比较
相同:都是为了提高复用性的一种手段,对系统开销基本类似
不同:继承高耦合性破坏封装特性
两者表达关系不同,继承is a ,组合时has a
1.1:对系统开销的理解
继承:子继承父,覆盖了父类方法,但是分配内存时还是要分配被覆盖的父类方法的内存空间
组合:分配组合类和被组合类的内存空间
两者对内存分配空间一样的,只不过组合在栈内存中存储了一个引用类型的变量
2:系统创建对象:加载,分配内存空间、初始化
3:extends规范:
1)对外提供访问的public,不对外private
2)对外提供但不让重写,用final
3)父类构造器尽量不要调用可以被子类重写的方法,可能报异常NPE
Fu{
Fu(){
test(){sop("wo shi fu");}
}
}
Zi extends Fu{
private String name;
test(){sop(name);}
//先调用父类构造器,父类构造器调用了被重写的方法,被重写的方法调用name未初始化
main(){
new Zi();
}
}
4:派生子类的情况
子类扩展了父类的属性;
子类扩展了自己特有的方式(增加新方法或者重写父类方法)
5:组合:把旧的对象作为新类的成员变量组合进来
Student{
private Animal animal;//用private修饰,用户看到的只是Student,实际Student调用了Animal
}
初始化块篇
1:类初始化块、普通初始化块
可以说初始化代码块时构造器的补充,先走代码块,再走构造器,都是为了初始化
只不过把那些共性的、且不需要入参的初始化代码抽出来作为代码块
初始化块被javac命令编译为class文件后不再存在,被还原到了构造器中
实际上在一个对象中可以存在多个代码块,根据定义顺序执行,但是没意义,都是隐形执行初始化,所以有一个就可以
声明成员变量时给变量初始化的操作,与代码块初始化的时机相同
2:静态初始化代码块、普通初始化代码块、构造器的执行顺序*****
与具有继承关系的对象创建子类对象时总是先执行父类构造器的情况相同
先执行父类静态代码块,依次走完所有父类静态代码块
再执行父类普通代码块,依次走完所有父类普通代码块
再执行父类构造器,依次走完所有父类构造器
同一类的实例对象创建时,静态代码块只初始化依次,, 每次实例化都要将普通代码块和构造器初始化依次