1. 程式人生 > >子類例項化是否會例項化父類?不會

子類例項化是否會例項化父類?不會

java中物件,與類在記憶體方面的理解,使得物件與類的概念具體點

  首先關於類,我們可以把它當成一個瓶子模具,這裡的模具只是用它的概念,不需要帶入真正的模具(因為瓶子沒有模具),當我們在
java中使用new來新建一個物件bottle時,可以想象成用這個模具去造了一個新瓶子,這個新瓶子是純粹一個瓶子,什麼花
紋都沒有,我們當成這個就是這個bottle的屬性的初始值,然後我們開始對這個新的物件bottle賦值,這個過程就像是在這個新的瓶子上面描上花紋的過程。

  那麼抽象類像什麼呢?抽象類,我們把它想象成半個瓶子模具,殘缺的,不完整,我們不能使用它去造一個新的瓶子,也就是new一個新的物件,那麼如何才能讓他變成一個完整的瓶子模具呢?

  我們會把它補全使它成為一個完整的瓶子模具,也就是在這個半個瓶子模具的基礎上,補全成為一個新的瓶子模具,就像是java的extends,擁有抽象父類的屬性,方法,同時實現抽象父類的抽象方法。

  繼續,Interface像什麼呢?花紋,純粹的花紋,當把這些花紋刻在模具上時,使用模具造出來的瓶子,也就有了這些花紋,就像是java中的類實現介面。

  現在談談子類繼承父類時,private屬性和方法,先只談談private屬性

/**
 * Created by 西皮 on 2017/9/17 14:23.
 */
public class FatherClass {

    private String name;

    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        System.out.println(this.toString());
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        System.out.println(this.toString());
    }

    @Override
    public String toString() {
        return "FatherClass{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

子類父類多一個fair

/**
 * Created by 西皮 on 2017/9/17 14:23.
 */
public class SonClass extends FatherClass{

    private String fair;

    private String name;

    private int age;

    public SonClass(){

    }

    public String getFair() {
        return fair;
    }

    public void setFair(String fair) {
        this.fair = fair;
        System.out.println(this.toString());
    }


    @Override
    public String toString() {
        return "SonClass{" +
                "fair='" + fair + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

先看一段測試程式碼:

@Test
public void testF(){
    SonClass son = new SonClass();
    FatherClass father = new FatherClass();
    father.setName("father");
    father.setAge(50);
    son.setName("son");
    son.setAge(18);
    son.setFair("有頭髮");
    System.out.println(son.toString());
    System.out.println(father.toString());
}

結果是:

這個可以說明在堆記憶體中,這個son指向的物件,裡面應該是有兩個name,和兩個age的一份是從父類繼承過來的,一份是自己的,而我們的toString方法,列印的是本類的屬性值。

那麼當我們加一句System.out.println(son.getName()+son.getAge());,可以很明顯得到son18的輸出

這裡必須說明的是,父類在子類例項化過程中是並沒有被例項化的

public SonClass(){
        super();//呼叫父類的構造器,但只是用來初始化屬性
        System.out.println(this.hashCode());
        System.out.println(super.hashCode());
        System.out.println(super.equals(this));
}

public FatherClass(){
    System.out.println(this.hashCode());
    System.out.println(super.hashCode());
    System.out.println(super.equals(this));
}

這裡分別在子類和父類中加入構造器,然後SonClass son = new SonClass();去除多餘的輸出,可以看到如下輸出:

這說明this和super都指向同一物件,這裡的hashCode值是jvm根據物件在記憶體中的地址生成的,是可以一一對應的。也就是,在子類構造器中,呼叫的super(),只是為了給繼承父類而來的屬性初始化

這裡我們補充一下jvm中的new指令的過程:

  jvm虛擬機器遇到一條new指令是如何工作的,遇到一條new指令,首先去檢查這個指令的引數
是否能在常量池中定位到一個類的符號引用,並且檢查這個符號引用代表的類是否已被載入、解析和初始化過。

  在類載入檢查通過後,接下來虛擬機器將為新生物件分配記憶體,在記憶體分配完成後,虛擬機器需要將分配到的記憶體空間都初始化為零值(不包括物件頭),接下來,虛擬機器要對物件進行必要的設定。。。。。。

  在上面的工作都完成之後,從虛擬機器的視角來看,一個新的物件已經產生了,但是這裡的屬性都是預設屬性,
現在我們需要把物件按程式設計師的意願初始化,也就是執行new指令之後會接著執行init方法。

以上是《深入理解java虛擬機器——jvm高階特性和最佳實踐》中對物件的建立的描述。

而在《Thinking in Java》94面中:無法阻止自動初始化的進行,他將在構造器被呼叫之前發生。

猜測一下,可以能java中建構函式是在new指令執行完畢之後,才進入建構函式,這樣建構函式也就是按程式設計師的意願初始化了。

總結一下,java中new SonClass並沒有例項化父類,只是呼叫父類的構造方法初始化了,子類從父類繼承來的屬性,這個呼叫是子類的物件呼叫的父類的構造方法,而子類自己的構造方法完成對自己屬性的初始化(這裡的初始化是指我們在記憶體分配完了,虛擬機器初始化之後,我們按自己的要求進行的初始化)

而private方法,也是和private屬性一樣的道理。

也就是子類其實是繼承了父類所有的屬性和方法,只是private的不能直接訪問而已,可以通過public等修飾的方法訪問他們。