2

問題

ある友人が興味深い問題を提案しました。次のコードがあるとします。

public class OuterClass {

    private String message = "Hello World";

    private class InnerClass {
        private String getMessage() {
            return message;
        }
    }

}

外部クラスから、message変数の内容を出力するにはどうすればよいですか? もちろん、メソッドやフィールドのアクセシビリティを変更することは許可されていません

(ソースはこちら、フランスのブログです)


解決

この問題を解決するコードは次のとおりです。

try {
    Method m = OuterClass.class.getDeclaredMethod("access$000", OuterClass.class);
    OuterClass outerClass = new OuterClass();
    System.out.println(m.invoke(outerClass, outerClass));
} catch (Exception e) {
    e.printStackTrace();
}

メソッド名は実際には標準的ではないことに注意してくださいaccess$000(この形式が強く推奨される形式であっても)、一部の JVM はこのメソッドに名前を付けますaccess$0。したがって、より良い解決策は、合成メソッドを確認することです。

Method method = null;
int i = 0;
while ((method == null) && (i < OuterClass.class.getDeclaredMethods().length)) {
    if (OuterClass.class.getDeclaredMethods()[i].isSynthetic()) {
        method = OuterClass.class.getDeclaredMethods()[i];
    }
    i++;
}
if (method != null) {
    try {
        System.out.println(method.invoke(null, new OuterClass()));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

したがって、この問題の興味深い点は、合成法の使用を強調することです。これらのメソッドを使用すると、ソリューションで行ったようにプライベート フィールドにアクセスできます。もちろん、リフレクションを使う必要がありますし、こういう使い方はかなり危険だと思いますが…

質問

開発者としての私にとって、合成メソッドの関心は何ですか? 合成繊維の使用が役立つ場合、どのような状況が考えられますか?

4

3 に答える 3

1

あなたが示しているように、Java アクセス修飾子は単なる情報提供であり、リフレクションを使用することで回避できます。したがって、あなたの質問は「アクセス修飾子を回避することの利点は何ですか?」とほぼ同じです。悪意のある目的とは別に、デバッグが思い浮かびます。たとえば、ライブラリのコード自体にまったく触れることなく、ライブラリの外部からライブラリの内部の内部状態をログに記録できます。もう 1 つの例は、スクリプト言語との連携です。コンパイル時にどのクラスとメソッドが利用可能かわからない場合、リフレクションは非常に便利です。たとえば、Jythonの内部では、あらゆる場所で大量の反射が使用されています。

于 2010-03-17T07:47:49.550 に答える
1

開発者としてのあなたにとって、合成メソッドの関心は何ですか? まず、それらを呼び出さないでください(他の回答者が説明した理由により)。

ただし、覚えておくべき興味深い点が 1 つあります。特に、セキュリティが重視される環境で実行する Java コードを作成している場合は、合成メソッドが攻撃者にプライベート フィールドへのバックドアを提供する可能性があるということです。

もちろん、そのような脆弱性が実際に問題になるには、いくつかの大きな「if」、つまり必要条件があります。

  1. 攻撃者は実際に JVM でコードを実行している必要があります。ほとんどの場合、これは問題ではありません。実行中のコードは自分のものだけだからです。
  2. 攻撃者のコードは、内部クラスと同じパッケージ内にある必要があります (合成メソッドがパッケージ プライベートと宣言されているため)。
  3. 攻撃者のコードは、クラスと同じクラスローダーからロードする必要があります。信頼できないコードを JVM で実行できるようにしている場合 (条件 1)、信頼できないコードには別のクラスローダーを使用することをお勧めします。
于 2010-03-17T07:48:20.093 に答える
0

リフレクションを使用して合成アクセサー メソッドを呼び出さないでください。使用するコンパイラによっては、変更される可能性があります。たとえば、私のマシンの jdk1.6 でソリューションを実行すると、access$000メソッドが見つからなかったため失敗しました。

合成アクセサーは、内部クラスが Java 1.1 に追加されたものであり、VM 仕様がそれらに対応するために変更されていないという事実を回避するための隠れたコンパイラ ハックです。

于 2010-03-17T07:41:08.900 に答える