子類擁有父類物件所有的屬性和方法,但無法訪問

worshipone發表於2024-04-23

原連結

前言

JavaGuide中關於繼承如下 3 點請記住:

  1. 子類擁有父類物件所有的屬性和方法(包括私有屬性和私有方法),但是父類中的私有屬性和方法子類是無法訪問,只是擁有。

嘗試驗證這一觀點。

物件初始化

首先從物件初始化開始思考,一般繼承某個父類的子類物件初始化時是按照以下順序:

  1. 父類的靜態變數和常量以及父類的靜態程式碼塊
  2. 子類的靜態變數和常量以及子類的靜態程式碼塊
  3. 父類的變數賦預設值和父類程式碼塊
  4. 父類的構造方法
  5. 子類的變數賦預設值和父類程式碼塊
  6. 子類的構造方法

既然按照物件初始化順序來說,子類的構造方法被呼叫的時候必然有一個父類物件被構造,那麼必然有辦法在子類構造時對父類的變數進行賦值。

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

其實從這裡就可以知道子類是擁有父類的私有屬性的了,只是因為訪問控制限制無法直接訪問這個屬性。
但是除了這個方法以外,我還有什麼辦法去佐證這個觀點呢?當然有啦,而且還不止一種呢,我知道的就有兩個辦法:

  1. 直接檢視位元組碼
  2. 使用反射獲取
    下面展示如何使用反射獲取父類的屬性的示例程式碼:
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

相關文章