23

私は持っている

class A {
    private static class B {
        B() {
        }
    }
}

B はプライベートですが、問題なく別のクラスから A$B.class をロードします。なぜそれが許されるのですか?

class C {
    public static void main(String[] args) throws Exception {
        System.out.println(Class.forName("A$B").newInstance());
    }
}

出力

A$B@affc70

アップデート

クラスをロードするための制限が意図的に引き上げられていることは理解していますが、それには合理的な説明が必要です。

パッケージのプライベート B{} コンストラクターは意図的にあることに注意してください。私がそれを削除すると、私は取得します

java.lang.IllegalAccessException: クラス B は修飾子 "private" を使用してクラス A$B のメンバーにアクセスできません

4

5 に答える 5

12

クラスローダーは任意のクラスをロードできますが、アクセスルールはインスタンス化時に適用されます。

では、なぜあなたのコードはクラスをインスタンス化できるのでしょうか?

内部クラスは、Java 1.0とバイトコード互換になるように実装されているため、バイトコードレベルでの大きなハックです。

したがって、ソースコードレベルのこのプライベート内部クラスは、実際にはバイトコードレベルでパッケージ保護されています。クラスCを別のパッケージに移動し、Bのコンストラクターを公開することで、次のことを確認できます。

Exception in thread "main" java.lang.IllegalAccessException: 
Class something.C can not access a member of class A$B with modifiers "public"

リフレクションでは、setAccessible()を使用してアクセスルールをオーバーライドできますが、ここではそうではありません。

于 2012-12-24T10:52:45.223 に答える
8

この動作はjavadocに準拠しています。

このメソッドは、要求されたクラスがその呼び出し元にアクセスできるかどうかをチェックしないことに注意してください。

つまり、forNameアクセスできないクラスにアクセスでき、IllegalAccessExcessException. また、コンストラクターはパッケージ プライベートであるため、呼び出し元の場所からアクセスできる (と思います) ため、newInstance例外もスローされません。

コンストラクターにアクセスできない場合 (別のパッケージに移動するか、プライベートにするため)、newInstance例外がスローされます。

更新に関しては、コンストラクターを削除すると、クラスと同じアクセス権を持つデフォルトのコンストラクターを呼び出すことになります。この場合はプライベートです ( JLS 8.8.3を参照:クラスがプライベートと宣言されている場合、デフォルトのコンストラクターは暗黙的にアクセス修飾子 private が与えられます)。

于 2012-12-24T11:16:17.567 に答える
3

リフレクションは、Java仮想マシンで実行されているアプリケーションの実行時の動作を調べたり変更したりする機能を必要とするプログラムで一般的に使用されます。

これは、いくつかのルールを破ることができるツールであり、足に投げたり、適切に使用したりすることができます。

リフレクションは、クラスとオブジェクト間の通常の相互作用では通常利用できない手段を介して、クラスに関する情報にアクセスするためのメカニズムを提供します。

その1つは、外部のクラスやオブジェクトからプライベートフィールドへのアクセスを許可することです。

ただし、とは両方ともgetDeclaredField()実際setAccessible()にはセキュリティマネージャによってチェックされ、コードでこれを行うことが許可されていない場合は例外がスローされます。多くのリフレクショントリックは、アクティブなセキュリティマネージャでは機能しない場合があります。

于 2012-12-24T10:53:34.093 に答える
3

リフレクションは良い比較ですが、クラス ローダーはリフレクション ライブラリの機能を超えています。たとえば、クラス ローダーはクラスを作成できますが、これはリフレクションでは作成できません。また、

  • 列挙型インスタンスの作成をトリガーします。
  • 初期化される前にクラスへの参照を提供します。
  • 親クラスローダーのクラスを「オーバーライド」します。
  • アンロード時にクラスをアンロードするようにトリガーします。
  • クラスのバイトコードを提供し、生の実装の詳細を提供します。
  • クラスパス内の非クラスリソースのストリームを提供します。

リフレクションと同様に、プライベート メンバーを含むクラスをロードできますが、ロードできなければ意味がありません。

于 2012-12-24T11:19:16.823 に答える
0

リフレクションの使用 モディファイアを変更することもできます

class MyClass{
private int value;
}

Field value = MyClass.class.getDeclaredField("value");
value.setAccessible(true);
于 2012-12-24T11:19:16.873 に答える