外部Javaクラスが内部クラスのプライベートメンバーにアクセスできるのはなぜですか?
-
05-07-2019 - |
質問
外部クラスが内部クラスのプライベートインスタンス変数にアクセスできることを確認しました。これはどのように可能ですか?同じことを示すサンプルコードを次に示します。
class ABC{
class XYZ{
private int x=10;
}
public static void main(String... args){
ABC.XYZ xx = new ABC().new XYZ();
System.out.println("Hello :: "+xx.x); ///Why is this allowed??
}
}
この動作が許可される理由
解決
内部クラスは、元の外部クラスに実際に属するいくつかの機能を明確に分離するための単なる方法です。これらは、2つの要件がある場合に使用することを目的としています。
- 外部クラスの一部の機能は、別のクラスに実装されている場合に最も明確になります。
- 別のクラスにあるにもかかわらず、機能は外部クラスの動作方法と非常に密接に結びついています。
これらの要件を考慮すると、内部クラスは外部クラスに完全にアクセスできます。基本的に外部クラスのメンバーであるため、プライベートを含む外部クラスのメソッドと属性にアクセスできることは理にかなっています。
他のヒント
内部クラスのプライベートメンバーを非表示にする場合は、パブリックメンバーでインターフェイスを定義し、このインターフェイスを実装する匿名の内部クラスを作成できます。以下の例:
class ABC{
private interface MyInterface{
void printInt();
}
private static MyInterface mMember = new MyInterface(){
private int x=10;
public void printInt(){
System.out.println(String.valueOf(x));
}
};
public static void main(String... args){
System.out.println("Hello :: "+mMember.x); ///not allowed
mMember.printInt(); // allowed
}
}
(アクセス制御の目的で)内部クラスは、収容クラスの一部と見なされます。これは、すべてのプライベートへのフルアクセスを意味します。
これを実装する方法は、パッケージで保護された合成メソッドを使用することです。内部クラスは、同じパッケージ(ABC $ XYZ)内の別のクラスにコンパイルされます。 JVMはこのレベルの分離を直接サポートしていないため、バイトコードレベルでABC $ XYZにはパッケージで保護されたメソッドがあり、外部クラスはプライベートメソッド/フィールドにアクセスするために使用します。
次のような別の質問に正しい答えが表示されます。 ネストされたクラスのプライベートメンバーに、包含するクラスのメソッドからアクセスできるのはなぜですか?
それ以外の場合、メンバーまたはコンストラクターがprivateとして宣言されている場合、アクセスは、メンバーの宣言を囲む最上位クラス(§ 7.6)の本体内で発生する場合にのみ許可されます。コンストラクタ。
内部クラスのIMHOの重要な使用例は、ファクトリパターンです。 包含クラスは、アクセス制限なしで内部クラスのインスタンスを準備し、プライベートアクセスが許可される外部世界にインスタンスを渡すことができます。
abyx クラスを静的に宣言しても、次に示すように、囲んでいるクラスへのアクセス制限は変更されません。また、同じ囲みクラスの静的クラス間のアクセス制限が機能しています。びっくりしました...
class MyPrivates {
static class Inner1 { private int test1 = 2; }
static class Inner2 { private int test2 = new Inner1().test1; }
public static void main(String[] args) {
System.out.println("Inner : "+new Inner2().test2);
}
}
アクセス制限はクラスごとに行われます。クラスで宣言されたメソッドが、すべてのインスタンス/クラスメンバーにアクセスできないようにする方法はありません。これは、内部クラスにも外部クラスのメンバーへの無制限のアクセス権があり、外部クラスには内部クラスのメンバーへの無制限のアクセス権があるためです。
クラスを別のクラス内に配置することで、実装に密接に結び付けられ、実装の一部であるものはすべて他の部分にアクセスできるようになります。
内部クラスの背後にあるロジックは、外部クラスで内部クラスを作成する場合、それはそれらがいくつかのことを共有する必要があるためであるため、「通常」よりも柔軟性を持たせることが理にかなっています;クラスが持っています。
あなたの場合、クラスが互いの内部動作を見ることができない場合-基本的に、内部クラスを単純に通常のクラスにした可能性があることを意味し、内部クラスを< code>静的クラスXYZ 。 static
を使用すると、状態を共有しなくなります(たとえば、 new ABC()。new XYZ()
は機能しません。を使用する必要があります> new ABC.XYZ()
。
ただし、その場合は、 XYZ
を実際に内部クラスにする必要があるかどうかを検討する必要があります。静的な内部クラスを作成することが理にかなっている場合があります(たとえば、外部クラスが使用しているインターフェイスを実装する小さなクラスが必要で、それ以外の場所では役に立たない場合)。しかし、約半分の時間で外部クラスにすべきでした。
Thiloは、最初の質問&quot;これはどのように可能ですか?&quot;に回答を追加しました。 2番目に尋ねられた質問について少し詳しく説明したいと思います。なぜこの動作が許可されているのですか?
まず最初に、この振る舞いは、定義により非静的なネストされた型である内部クラスにのみ許可されないことを完全に明確にしましょう。この動作は、静的である必要があり、囲むインスタンスを持つことができないネストされた列挙型およびインターフェイスを含む、すべてのネストされた型で許可されます。基本的に、このモデルは次のステートメントまで簡略化されています。ネストされたコードは、囲んでいるコードに完全にアクセスできます。逆も同様です。
だから、なぜですか?例がポイントをよりよく示していると思います。
身体と脳について考えてください。ヘロインを腕に注入すると、脳が高くなります。あなたの脳の扁桃体領域が、彼があなたの個人的な安全への脅威であると信じているもの、例えばスズメバチを見ると、彼はあなたの体を逆向きにし、あなたが「考える」ことなく丘に向かって走ります。約2回。
つまり、脳は身体の本質的な部分であり、奇妙なことに、逆もまた同様です。このような密接に関連するエンティティ間でアクセス制御を使用すると、関係を主張できなくなります。アクセス制御が必要な場合は、クラスをさらに明確なユニットにさらに分ける必要があります。それまでは、同じユニットです。さらなる研究の推進例は、Java イテレータ
は通常実装されています。
囲んでいるコードからネストされたコードへの無制限のアクセスは、ほとんどの場合、ネストされた型のフィールドとメソッドにアクセス修飾子を追加するのではなく、役に立たないものにします。そうすることは混乱を追加することであり、Javaプログラミング言語の新規参入者に誤った安全感を与える可能性があります。
内部クラスは外部クラスの属性と見なされます。したがって、Innerクラスのインスタンス変数がプライベートであるかどうかに関係なく、Outerクラスは他のプライベート属性(変数)にアクセスするのと同じように問題なくアクセスできます。
class Outer{
private int a;
class Inner{
private int b=0;
}
void outMethod(){
a = new Inner().b;
}
}
main()
メソッドは ABC
クラスにあるため、このクラスは独自の内部クラスにアクセスできます。