關於繼承與多態

 關於繼承與多態的幾點總結

一、父類的全部方法都能被繼承嗎?能被重寫嗎?能表現出多態性嗎?

1.1 非靜態方法

  1.1.1 被public、default、protected修飾的非靜態方法

  能被子類繼承,若是沒有被final修飾,則能被重寫,當父類引用指向子類對象時,表現出多態性。java

  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 靜態方法

  靜態方法能夠被繼承,不能被重寫,也就不能表現出多態性this

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();
    }
}

打印結果:spa

parent
child

 1.3 構造方法

  構造方法不能被繼承,不能被重寫,沒有多態性。code

  構造方法既不是靜態方法也不是非靜態方法,構造方法中會有一個this對象做爲參數傳進去,因此咱們能夠在構造方法內部對對象屬性進行初始化,也能夠在構造方法內調用非靜態方法。對象

  若是該非靜態方法被重寫過,那麼構造器內部會不會存在多態行爲呢?參考Java編程思想中的一個例子:blog

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);
    }
}

 

  在父類構造器中調用被子類重寫的非靜態方法,會發生多態行爲,但這並非咱們想要的結果,緣由以下:繼承

  1. 在其餘任何事物發生以前,將分配給對象的存儲空間初始化爲二進制的零;
  2. 如前所述那樣調用基類構造器。此時,調用被覆蓋後的draw()方法(要在調用RoundGlyph構造器以前調用),因爲步驟1的緣故,咱們此時會發現radius的值爲0;
  3. 按照聲明的順序調用成員的初始化方法;
  4. 調用導出類的構造器主體。

  所以,在編寫構造器中有一條有效的準則:「用盡量簡單的方法使對象進入正常狀態;若是能夠的話,避免調用其餘方法」。在構造器中,惟一可以安全調用的是基類中的final方法(包括private方法),由於這些方法不能被子類覆蓋,也就不會出現上述的問題。get

二、父類的全部屬性都能被繼承嗎?能被重寫嗎?能表現出多態性嗎?

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虛擬機的原理再來完善!

相關文章
相關標籤/搜索