天天看點

java 反射父類私有屬性_如何證明Java子類實際上是擁有父類的私有屬性

前言

最近在看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