外部Javaクラスが内部クラスのプライベートメンバーにアクセスできるのはなぜですか?


177

外部クラスが内部クラスのプライベートインスタンス変数にアクセスできることを確認しました。これはどのようにして可能ですか?以下は、同じことを示すサンプルコードです。

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??
    }
}

この動作が許可されるのはなぜですか?


この質問は、私はコメントが表示されるまで...それは説明かなりしばらくの間、私を混乱なぜ私は私のマシンではないアクセスxx.xのでき...
王盛

4
コメントで混乱しました。Java8で上記のコードを実行しますが、コンパイルして実行します。xx.xにアクセスできます。
レオン2016

了解しました。受け入れられた回答(あなたが尋ねた質問には回答しません)の受け入れを解除して、代わりに下記のMartin Anderssonの回答を受け入れてください。
temporary_user_name

FWIWこの構文は恐ろしいです:new ABC().new XYZ()
ジョシュM.

回答:


80

内部クラスは、元の外部クラスに実際に属する一部の機能を明確に分離するための方法にすぎません。次の2つの要件がある場合に使用することを目的としています。

  1. 外部クラスの機能の一部は、別のクラスで実装された場合に最も明確になります。
  2. 別のクラスにある場合でも、機能は外部クラスの機能と密接に関連しています。

これらの要件を前提として、内部クラスは外部クラスに完全にアクセスできます。それらは基本的に外部クラスのメンバーなので、プライベートを含む外部クラスのメソッドと属性にアクセスできることは理にかなっています。


217
この回答は、ネストされたクラスが外部クラスのプライベートメンバーにアクセスできる理由を説明しています。しかし問題は、なぜ外部クラスがネストされたクラスのプライベートメンバーにアクセスできるのかということです。
Andrew

13
これらの要件を前提として、「逆も同様」を追加するだけで、内部クラスは外部クラスに完全にアクセスでき、質問に答えます。
anthropomo

13
この1はここでは、この問題に対する正しい答えではないん:stackoverflow.com/questions/19747812/...
コリン・蘇

4
@anthropomo:いいえ、ありません。どちらの要件も、外部クラスが内部クラスのプライベートメンバーにアクセスできない場合でも、完全に実現可能です。
またはMapper '16 / 12/16

これが特に役立つ1つの良い例は、ビルダーパターン、stackoverflow.com / a / 1953567/1262000です。親クラスには、ビルダーを取り、そのすべてのメンバー変数にアクセスするコンストラクターが必要です。それ以外の場合は、すべてのプライベートメンバー変数を持つ親コンストラクターにプライベートコンストラクターが必要になります。
vikky.rk

62

内部クラスのプライベートメンバーを非表示にする場合は、パブリックメンバーを使用してインターフェイスを定義し、このインターフェイスを実装する匿名の内部クラスを作成できます。以下の例:

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

これは見事なコードの断片です。ちょうど私が必要としたもの。ありがとう!
kevinarpe 2013年

実行できるコードを提供してください。さらに、プライベート変数にアクセスを許可できなかった理由を教えてください。
androidyue 2014年

7
しかし、その後...内部クラスは匿名です。あなたは、いくつかのその内部クラスのインスタンス、または使用を作成することができない内側の任意の変数宣言のためのクラスなど
ORマッパー

@OR Mapperがx、ここで公開されている場合でも、のように許可されていませんmMember.x
MAC

54

内部クラスは(アクセス制御の目的で)包含クラスの一部と見なされます。これは、すべてのプライベートへのフルアクセスを意味します。

これを実装する方法は、合成パッケージで保護されたメソッドを使用しています。内部クラスは、同じパッケージ(ABC $ XYZ)の別のクラスにコンパイルされます。JVMはこのレベルの分離を直接サポートしていないため、バイトコードレベルのABC $ XYZには、外部クラスがプライベートメソッド/フィールドに到達するために使用するパッケージ保護されたメソッドがあります。


17

これに似た別の質問に正解があります: ネストされたクラスのプライベートメンバーに、囲んでいるクラスのメソッドがアクセスできるのはなぜですか?

JLSのプライベートスコーピングの定義-アクセシビリティの決定

それ以外の場合、メンバーまたはコンストラクターがプライベートとして宣言されていると、メンバーまたはコンストラクターの宣言を囲むトップレベルクラス(§7.6)の本文内でアクセスが許可されます。


このスニペットは私の質問にうまく答えることができると思います。
2017

5

内部クラスの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);
    }
}

1
いいコメントですが答えはありません。
2013

@cervingこれは、実際にはこの奇妙な設計決定の実際の実際の使用方法を確認できる唯一の回答です。問題は、なぜこのように決定されたかであり、これは大きな理由です-外部クラスに内部クラスでアクセスさせたいものと他の無関係なクラスにアクセスさせたいものとの違いのデモンストレーションです。
et_l 2016

3

アクセス制限はクラスごとに行われます。クラスで宣言されたメソッドがすべてのインスタンス/クラスメンバーにアクセスできないようにする方法はありません。これは、内部クラスにも外部クラスのメンバーへの自由なアクセスがあり、外部クラスには内部クラスのメンバーへの自由なアクセスがあることは当然のことです。

クラスを別のクラス内に配置することで、クラスを実装に密接に結び付け、実装の一部であるものはすべて他の部分にアクセスできるようになります。


3

内部クラスの背後にある論理は、外部クラスに内部クラスを作成する場合、それらはいくつかのことを共有する必要があるためであり、したがって、「通常の」クラスよりも柔軟性を持たせることが理にかなっています。

あなたの場合、クラスが互いの内部の仕組みを見ることができないのは意味がありません-これは基本的に、内部クラスが単に通常のクラスにされている可能性があることを意味し、内部クラスをとして宣言できますstatic class XYZ。使用staticすると、それらは状態を共有しないことを意味します(たとえば、機能new ABC().new XYZ()せず、を使用する必要がありますnew ABC.XYZ()
しかし、そうである場合は、XYZ本当に内部クラスである必要があるかどうか、独自のクラスである必要があるかどうかを検討する必要があります。ファイル。静的な内部クラスを作成することが理にかなっている場合があります(たとえば、外部クラスが使用しているインターフェースを実装する小さなクラスが必要で、他の場所では役に立たない場合)。ただし、半分の時間でそれは外部クラスにすべきでした。


2
外部クラスは静的内部クラスのプライベートメンバーにも同様にアクセスできるため、これはstaticとは関係ありません。あなたは「クラスが互いの内部の仕組みを見ることができるのは意味がない」と言いますが、それは必ずしもそうではありません-内部クラスが外部クラスの内部の仕組みを見るだけで意味があるが、その逆ではない場合はどうでしょうか-逆?
またはMapper

3

ティロはあなたの最初の質問「これはどうして可能ですか?」に良い答えを追加しました。2番目の質問について少し詳しく説明したいと思います。なぜこの動作が許可されるのですか?

手始めに、この動作は内部クラスに限定されないことを完全に明確にしましょう。これは、定義上、静的でないネストされた型です。この動作は、静的である必要があり、囲んでいるインスタンスを持つことができない、ネストされた列挙型とインターフェースを含む、すべてのネストされた型に対して許可されます。基本的に、モデルは次のステートメントまで簡略化されています。ネストされたコードは、囲んでいるコードへの完全なアクセス権を持ち、その逆も同様です。

では、なぜでしょうか。私は例がその点をよりよく示していると思います。

あなたの体とあなたの脳を考えてください。ヘロインを腕に注入すると、脳が高くなります。あなたの脳の扁桃体領域が、あなたの個人的な安全に対する脅威であると彼が信じているもの、たとえばスズメバチを見つけた場合、彼はあなたの体を反対方向に向けさせ、あなたがそれについて2度「考える」ことなく丘に向かって走ります。

ですから、脳は体の本質的な部分です-そして奇妙なことに、逆もまた同様です。このような密接に関連するエンティティ間のアクセス制御を使用すると、関係の主張が失われます。アクセス制御が必要な場合は、クラスをさらに明確なユニットにさらに分離する必要があります。それまでは同じユニットです。さらなる研究の原動力となる例は、JavaがIterator通常どのように実装されているかを見ることです。

囲んでいるコードからネストされたコードへの無制限のアクセスは、ほとんどの場合、ネストされた型のフィールドおよびメソッドにアクセス修飾子を追加するのにかなり役に立たないものにします。そうすることで混乱が増し、Javaプログラミング言語の新参者に誤った安心感を与える可能性があります。


1
これは実際に受け入れられる答えになるはずです。とても明確で完全です。代わりに、受け入れられた答えは質問に対処することすらありません。
temporary_user_name

IMOこれでも、外部クラスが直接アクセスできない内部フィールドにプライベートフィールドを簡単に追加できない理由についての質問には答えません。私が間違っていない限り、これは内部クラスの主要なケースの1つを台無しにします-短命な「構造体のような」不変の型を作成します。FWIW C#はこれをサポートしています:repl.it/repls/VengefulCheeryInverse
Josh M.

-1

内部クラスは外部クラスの属性と見なされます。したがって、内部クラスのインスタンス変数がプライベートであるかどうかに関係なく、外部クラスは他のプライベート属性(変数)にアクセスするのと同じように問題なくアクセスできます。

class Outer{

private int a;

class Inner{
private int b=0;
}

void outMethod(){
a = new Inner().b;
}
}

-2

あなたのためmain()の方法がであるABCクラス、できる独自の内部クラスにアクセスします。


2
問題は、ABCクラスのメンバーがクラスにネストされたABCクラスにアクセスできるかどうかではなく、Javaのクラスにネストされたクラスのプライベートメンバーにアクセスできる理由ABCです。
またはMapper

私は質問されたその日に質問に答えました。2年後に誰かが質問を編集し、3年後に反対票が出されました。質問を編集した人が質問の文言をまったく変更しすぎたと思います。
aberrant80
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.