yohhoyの日記

技術的メモをしていきたい日記

スーパークラスのprivateフィールドにアクセス

プログラミング言語Javaでは、スーパークラスのprivateフィールドはサブクラスへ継承(inherited by)されず、原則としてスーパークラス外部からはアクセスできない。ただし特定の条件下において、サブクラスからスーパクラスprivateフィールドへのアクセスが可能となる。*1

class AccessibleTrick {
  // スーパークラス
  static class Superclass {
    private int secret = 42;
  }

  // スーパークラスを継承したサブクラス
  static class Subclass extends Superclass {
    void spySecretValue() {
      int value;
      value = this.secret; // NG: コンパイルエラー
      // error: secret has private access in Superclass

      value = ((Superclass)this).secret;
      // OK: スーパークラスprivateフィールドにアクセス
    }
  }

  public static void main(String[] args) {
    Subclass obj = new Subclass();
    obj.spySecretValue();
  }
}

対象となるスーパークラスSuperclass/サブクラスSubclassともに、同じクラスAccessibleTrick入れ子クラス(nested class)*2であるときに限ってprivateフィールドへのアクセスが許可される。Java Language Specification, Java SE 8 Editionより一部引用。

  • A member (class, interface, field, or method) of a reference type, or a constructor of a class type, is accessible only if the type is accessible and the member or constructor is declared to permit access:
    • (snip)
    • Otherwise, the member or constructor is declared private, and access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.
Chapter 6. Names, 6.6.1. Determining Accessibility

A private field of a superclass might be accessible to a subclass - for example, if both classes are members of the same class. Nevertheless, a private field is never inherited by a subclass.

Chapter 8. Classes, 8.3. Field Declarations

ノート:本記事はJLS §8.3 "A private field of a superclass might be accessible to a subclass"を動機としているため、継承関係にあるクラス間のprivateフィールドにフォーカスしている。JLS §6.6.1に従えば、継承関係のない入れ子クラス同士であっても相互のprivateフィールドアクセスが可能。

関連URL

*1:本記事では「リフレクション(reflection)」は考慮しない。なお、JavaセキュリティマネージャによってはsetAccessibleメソッド呼び出しを拒否する。

*2:公式The Java Tutorialsによれば、入れ子クラス(nested class)=static/非staticクラス、インナークラス(inner class)=非staticクラスを指す用語らしい。