LoginSignup
15
10

More than 5 years have passed since last update.

[Java]同一クラスであれば他インスタンスのprivateフィールドにアクセスできるのは何故か?

Posted at

概要

Javaのprivateフィールドのアクセス権について

こちらの投稿を読んで、同じクラスであれば他インスタンスの private フィールドにアクセスできてしまうのは何故か?について気になったので考察してみました。

具体例

Main.java
class Main {
  public void static main(String[] args) {
    Something obj1 = new Something("foo");
    Something obj2 = new Something("bar");

    // bar と出力される
    System.out.println(obj1.extractName(obj2));
  }
}
Something.java
class Something {
  private String name;

  /**
   * コンストラクタ
   */
  public Something(String name) {
    this.name = name;
  }

  /**
   * 引数に渡されたオブジェクトの private なフィールドを取得する
   */
  public String extractName(Something other) {
    return other.name; // ここで他のインスタンスの private フィールドにアクセスできてしまうことに違和感がある
  }
}

本質的には Getter で private フィールドを返すのと同じことなんじゃないだろうか?

一般的な Getter は以下のように定義しますが、

class Something {
  private String name;

  public Something(String name) {
    this.name = name;
  }

  public String getName() {
    return this.name;
  }
}

ちょっと書き方を変えてみると次のようにも書けます。
※ this を他の変数に格納する、ということはあまりやらないと思いますが問題なく動きます

  public String getName() {
    Something instance = this;
    return instance.name;
  }

これは前出の Something#extractName メソッドでやっていることと本質的には変わらない。
どちらも、Something 型のオブジェクトの private フィールドである name にアクセスし、値を返している。

private フィールドへのアクセスに関する誤解

これまで「private で宣言されたフィールドには this を通して、そのインスタンス自身からしかアクセスできない」というような認識でしたがおそらくそれは正確ではなく、次のように考えれば統一的に理解できます。

  • 大前提として、フィールドには instance.fieldName という形でアクセスする
  • public なフィールドはプログラムのどこでも instance.fieldName という形でアクセス可能
  • private なフィールドはそのクラス定義内であれば instance.fieldName という形でアクセス可能
  • this はそのインスタンス自身の参照が入っているだけで他の変数と変わらない

つまり、普段 private フィールドへのアクセスが this.name のように記述できているのは、「そのインスタンスのフィールドだから」ではなく、「Something クラス内では (Somethingクラスのインスタンス).name という形でのprivateフィールドへのアクセスが許可されているから」である、ということのようです。

メソッドの場合

試してみたところメソッドでも同じです。
他インスタンスの private メソッドを呼び出せています。

Main.java
public class Main {
    public static void main(String[] args) throws Exception {
        Something obj1 = new Something("foo");
        Something obj2 = new Something("bar");

        // obj2 内の private メソッドが呼び出され、
        // My name is bar と出力される
        obj1.test(obj2);
    }
}
Something.java
class Something {
    private String name;

    public Something(String name) {
        this.name = name;
    }

    private void privateMethod() {
        System.out.println("My name is " + this.name);
    }

    public void test(Something other) {
        other.privateMethod();
    }
}
15
10
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
10