子類例項化是否會例項化父類?不會
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等修飾的方法訪問他們。