簡體   English   中英

Java:從內部 class 訪問受保護的字段

[英]Java: accessing protected fields from inner class

Recently I've faced a problem getting a runtime error java.lang.IllegalAccessError when trying to access from inner class a protected field declared in outer's parent class that was loaded by a different class loader. 簡要地:

  1. Class Parent具有受保護的字段p
  2. Class Outer擴展Parent
  3. Class Inner是在 class Outer中定義的內部 class 。
  4. Inner class 里面有一個代碼: Outer.this.p
  5. 所有類都在同一個 package 中聲明。

通常它會編譯並運行良好,直到ParentOuter class 由不同的 class 加載程序加載。 在這種情況下,我們在嘗試從Inner訪問Outer.this.p時得到java.lang.IllegalAccessError 我發現了一個舊的錯誤報告(這似乎是一個功能)描述了這種行為:

https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6258289

但分辨率聽起來與我矛盾:

關鍵是,在失敗的情況下,內部 class 不在同一個 package(並且不是 ConcreteCommand/AbstractCommand 的子類)中。 這完全違反了受保護類的 Java 規范。

聽起來是正確的。 但是,如果我們在不同的包中聲明ParentOuter類,但使用單個 class 加載器加載(只需創建沒有任何 jar 加載的示例控制台應用程序),我們不會收到任何錯誤。 所以從技術上講,它違反了 Java 規范的受保護類,但由於我們使用內部 class 它可以工作。

因此,對於兩種“不同包”的情況,我們有不同的行為。

  1. 在不同的包中聲明,由單個 class 加載程序加載 - 好的。
  2. 在單個 package 中聲明,由不同的 class 加載器加載 - 不正常。

有人可以清楚地解釋內部 class 如何訪問父字段以及為什么它在兩種情況下的工作方式不同?

  • 相同的 class 加載器似乎正在工作
  • 我問對了嗎?
  • 您是否有任何單元測試用例來重現您的問題?

父 Class

package p1;

public class Parent {
    
    protected String p = "Value from Parent";
    
    public void test() {
        System.out.println(p);
    }

}

外 Class

package p1;

public class Outer extends Parent {

    class Inner {
        public void test() {
            Outer.this.p = "Value set from Inner";
            System.out.println(Outer.this.p);
        }
    }

    public void test() {
        new Inner().test();
    }
}

主Class

package p1;

public class Main {

    public static void main(String[] args) {
        Parent p = new Parent();
        p.test();
        p = new Outer();
        p.test();
    }
}

Output

Value from Parent
Value set from Inner

在不同的包中聲明,由單個 class 加載程序加載 - OK

“受保護”訪問考慮到類之間的父子關系,並允許子類訪問父類的“受保護”成員,即使它們位於不同的包中。 所以,我認為這符合預期。

在單個 package 中聲明,由不同的 class 加載器加載 - 不正常

這與運行時包有關。 檢查這個 現在我們知道,由於通過兩個不同的 class 加載程序加載,Parent 與 Outer 和 Inner 處於不同的運行時 package 中。 同時,我們還必須記住,Outer 是 Parent 的“孩子”,而 Inner 不是。 Inner 與 Parent 沒有“Is-a”關系。

綜上所述:由於 Parent 位於不同的運行時 package 中,因此 Inner 無法訪問 Parent 的“受保護”成員,因為 Inner 不是 Parent 的孩子。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM