前言
最近在看JavaGuide進行基礎知識的回顧,注意到一個有意思的觀點,原文如下
關于繼承如下 3 點請記住:
子類擁有父類對象所有的屬性和方法(包括私有屬性和私有方法),但是父類中的私有屬性和方法子類是無法通路,隻是擁有。
于是我就開始嘗試驗證這一觀點
對象初始化
首先從對象初始化開始思考,一般繼承某個父類的子類對象初始化時是按照以下順序(對這塊感興趣的可以給我留言 )
父類的靜态變量和常量以及父類的靜态代碼塊
子類的靜态變量和常量以及子類的靜态代碼塊
父類的變量賦預設值和父類代碼塊
父類的構造方法
子類的變量賦預設值和父類代碼塊
子類的構造方法
既然按照對象初始化順序來說,子類的構造方法被調用的時候必然有一個父類對象被構造,那麼必然有辦法在子類構造時對父類的變量進行指派。
這個時候我突然想到了Java如果不指定構造方法,會預設給每個類提供一個無參構造方法,那如果我的父類隻有有參構造方法又會如何呢?
使用有參構造方法
首先我準備好了父類,這個父類裡面隻有一個parentName的屬性,同時制定一個有參構造方法,代碼如下:
public class Parent {
private String parentName;
public Parent(String parentName) {
this.parentName = parentName;
}
}
然後我準備了子類繼承父類,這個時候有意思的事情發生了,子類必須提供一個帶參的構造方法來構造父類對象,同時要在這個帶參構造方法裡面通過super關鍵字調用父類的構造方法,否則編譯會失敗,最終代碼如下:
public class Child extends Parent{
public Child(String parentName) {
super(parentName);
}
}
其實從這裡就可以知道子類是擁有父類的私有屬性的了,隻是因為通路控制限制無法直接通路這個屬性。
但是除了這個方法以外,我還有什麼辦法去佐證這個觀點呢?當然有啦,而且還不止一種呢,我知道的就有兩個辦法
直接檢視位元組碼
使用反射擷取
使用反射擷取
由于篇幅問題,這裡就展示怎麼使用反射擷取父類的屬性的示例代碼,如果對通過位元組碼驗證這個觀點感興趣可以給我留言:
Child child = new Child("David");
try {
// 擷取父類Class對象
Class parentClass = child.getClass().getSuperclass();
// 擷取父類的屬性
Field field = parentClass.getDeclaredField("parentName");
// 解除通路限制
field.setAccessible(true);
// 輸出
System.out.println(field.get(child));
} catch (NoSuchFieldException e) {
// 這裡隻是示範用,實際開發時需要将錯誤資訊列印到日志檔案
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
輸出結果
David