關於繼承與多態的幾點總結 1、父類的所有方法都能被繼承嗎?能被重寫嗎?能表現出多態性嗎? 1.1 非靜態方法 1.1.1 被public、default、protected修飾的非靜態方法 能被子類繼承,如果沒有被final修飾,則能被重寫,當父類引用指向子類對象時,表現出多態性。 1.1.2 被p ...
關於繼承與多態的幾點總結
1、父類的所有方法都能被繼承嗎?能被重寫嗎?能表現出多態性嗎?
1.1 非靜態方法
1.1.1 被public、default、protected修飾的非靜態方法
能被子類繼承,如果沒有被final修飾,則能被重寫,當父類引用指向子類對象時,表現出多態性。
1.1.2 被private修飾的非靜態方法
不能被子類繼承,更不能被重寫,沒有多態性(有的人理解為父類的所有包括私有的成員都能被繼承,只是在子類中不可見,我更傾向於前者)。當子類中出現與父類私有方法名和參數相同的時候會發生什麼呢?
class Parent{ private void f() { System.out.println("parent"); } public static void main(String[] args) { Parent p = new Child(); p.f(); } } class Child extends Parent{ public void f() { //父類的私有方法在子類中不可見,子類的f()方法是一個全新的方法,編譯器認為f()方法沒有被重寫
System.out.println("child");
}
}
列印結果:
parent
1.2 靜態方法
靜態方法可以被繼承,不能被重寫,也就不能表現出多態性
class Parent{
public static void f() {
System.out.println("parent");
}
}
class Child extends Parent{
public static void f() {
System.out.println("child");
}
public static void main(String[] args) {
Parent p = new Child(); //靜態方法能被繼承,但不能被重寫
p.f();
Child c = new Child();
c.f();
}
}
列印結果:
parent
child
1.3 構造方法
構造方法不能被繼承,不能被重寫,沒有多態性。
構造方法既不是靜態方法也不是非靜態方法,構造方法中會有一個this對象作為參數傳進去,所以我們可以在構造方法內部對對象屬性進行初始化,也可以在構造方法內調用非靜態方法。
如果該非靜態方法被重寫過,那麼構造器內部會不會存在多態行為呢?參考Java編程思想中的一個例子:
class Glyph {
void draw() {
System.out.println("Glyph.draw()");
}
Glyph() {
System.out.println("Glyph() before draw()");
draw();
System.out.println("Glyph() after draw()");
}
}
class RoundGlyph extends Glyph {
private int radius = 1;
RoundGlyph(int r) {
radius = r;
System.out.println("RoundGlyph.RoundGLyph(), radius = " + radius);
}
void draw() {
System.out.println("RoundGlyph.draw(), radius = " + radius);
}
}
class RolyConstructors {
public static void main(String[] args) {
new RoundGlyph(5);
}
}
在父類構造器中調用被子類重寫的非靜態方法,會發生多態行為,但這並不是我們想要的結果,原因如下:
- 在其他任何事物發生之前,將分配給對象的存儲空間初始化為二進位的零;
- 如前所述那樣調用基類構造器。此時,調用被覆蓋後的draw()方法(要在調用RoundGlyph構造器之前調用),由於步驟1的緣故,我們此時會發現radius的值為0;
- 按照聲明的順序調用成員的初始化方法;
- 調用導出類的構造器主體。
因此,在編寫構造器中有一條有效的準則:“用儘可能簡單的方法使對象進入正常狀態;如果可以的話,避免調用其他方法”。在構造器中,唯一能夠安全調用的是基類中的final方法(包括private方法),因為這些方法不能被子類覆蓋,也就不會出現上述的問題。
2、父類的所有屬性都能被繼承嗎?能被重寫嗎?能表現出多態性嗎?
2.1 被public,default,protected修飾的屬性
都能被繼承(與是否是靜態的無關),不能被重寫,沒有多態性。當子類中定義了與父類相同的屬性時,子類會在不同的存儲空間同時保留自己的和父類的屬性
class Child extends Parent {
public static int a = 2;
public void getA() {
System.out.println("a = "+a);
}
public void ParentA() {
System.out.println("super.a = " + super.a);
}
public static void main(String[] args) {
Parent p = new Child();
System.out.println(p.a); //任何域訪問操作都由編譯器解析
Child c = new Child();
c.getA(); //直接訪問field預設會獲取自己的域
c.ParentA(); //通過super.field能獲取父類的域
}
}
2.1 被private修飾的屬性
個人理解為可以被繼承,但是不能直接訪問,能通過父類public、default、或protected方法間接訪問(也有人理解為不能為繼承)
class Parent {
private int a;
public Parent(int a) {
this.a = a;
}
public int getA() {
return a;
}
}
class Child extends Parent {
public Child(int a) {
super(a);
}
public static void main(String[] args) {
Child c = new Child(1);
System.out.println(c.getA()); //結果為1
}
}
當父類和子類存在相同私有屬性時:
class Parent {
private int a;
public Parent(int a) {
this.a = a;
}
public int getA() {
return a;
}
}
class Child extends Parent {
private int a = 2;
public Child(int a) {
super(a);
}
public static void main(String[] args) {
Child c = new Child(1);
System.out.println(c.getA()); //1
System.out.println(c.a); //2
}
}
關於繼承與多態以及對象初始化過程還有很多不是很理解的地方,先記錄下來,等日後有時間研究一下java虛擬機的原理再來完善!