@
抽象类的特点:
A:抽象类和抽象方法必须用abstract关键字修饰
B:抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类
C:抽象类不能实例化
因为它不是具体的。
抽象类有构造方法,但是不能实例化?构造方法的作用是什么呢?
用于子类访问父类数据的初始化
D:抽象的子类
a:如果不想重写抽象方法,该子类是一个抽象类。
b:重写所有的抽象方法,这个时候子类是一个具体的类。
抽象类的实例化其实是靠具体的子类实现的。是多态的方式。
Animal a = new Cat();
多态其实主要用于 抽象类和其具体子类。而不是具体类和具体类之间。
抽象类和接口的区别:
A:成员区别
抽象类:
成员变量:可以变量,也可以常量
构造方法:有
成员方法:可以抽象,也可以非抽象
接口:
成员变量:只可以常量 默认public static final
成员方法:只可以抽象 默认public abstract
B:关系区别
类与类
继承,单继承
类与接口
实现,单实现,多实现
接口与接口
继承,单继承,多继承
C:设计理念区别
抽象类 被继承体现的是:”is a”的关系。抽象类中定义的是该继承体系的共性功能。
接口 被实现体现的是:”like a”的关系。接口中定义的是该继承体系的扩展功能。
为什么new子类要先执行父类构造方法
其实之前一直不明白构造函数“初始化”的含义。一直以为 “初始化”==“变量赋值”,其实初始化的内涵不是这样的。
class Person{...}
class Student extends Person{...}
对于Student stu = new Student(),更合理的解释是:
1, 加载class文件
5, 父类静态变量加载到方法区
6, 父类静态代码块初始化变量
7, 子类静态变量加载到方法区
8, 子类静态代码块初始化变量
2, 加载main方法在栈内存中(类被加载后,虚拟机再调用静态方法main。类加载会先走静态代码块,注定静态代码块 先于main)
3, 在栈内存中开辟空间给Student stu(对象引用的空间)
4, new申请堆内存空间(对象的空间)
9, 父类变量默认初始化、显示初始化(一般只有默认初始化,创建一个学生类时不会直接写age=20,这样以后每个创建的对象一开始就20岁)
10, 父类构造代码块初始化(如果有赋值语句)
11, 父类构造器初始化(如果有赋值语句)
12, 子类变量默认初始化、显示初始化(一般只有默认初始化,创建一个学生类时不会直接写age=20,这样以后每个创建的对象一开始就20岁)
13, 子类构造代码块初始化(如果有赋值语句)
14, 子类构造器初始化(如果有赋值语句)
最后,把对象地址赋值给stu
详见:
http://bbs.csdn.net/topics/380077372
http://www.jb51.net/article/37881.htm
http://bbs.csdn.net/topics/260013819
多态的弊端及解决办法
弊端:Fu f = new Zi() f不能用子类特有方法。
解决办法: Zi z = (Zi)f; 由于本身是子类对象,可以向下转型会子类引用,再调用子类特有方法。
继承和多态中成员访问的特点总结
继承是站在子类的角度,多态是站在父类的角度。
继承时,子类为观察者,发起者。不论是成员变量还是成员方法,都是遵照就近原则。
子类变量会被优先调用。
而子类方法会覆盖父类方法。
所以,同名情况下,子类都先使用自己的。
多态中,父类为观察者,发起者。
父类自己的变量会优先调用,而且不存在调用子类变量的情况。因为,调用子类变量说明变量名不同,说明是子类后加上去的。父类中是没有get该变量的方法的!
父类方法会被子类方法覆盖。
所以同名曲情况下,父类使用自己的变量,使用子类的方法。
实际开发中,使用继承一般更多的是为了复用性,为了重写父类方法。很少涉及变量(子类自己的)。
使用多态一般更多的是为了可维护性,为了同一个引用调用不同子类的特有同名方法。很少涉及变量(父类自己的)。