@
抽象類的特點:
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該變量的方法的!
父類方法會被子類方法覆蓋。
所以同名曲情況下,父類使用自己的變量,使用子類的方法。
實際開發中,使用繼承一般更多的是為了復用性,為了重寫父類方法。很少涉及變量(子類自己的)。
使用多態一般更多的是為了可維護性,為了同一個引用調用不同子類的特有同名方法。很少涉及變量(父類自己的)。