2

リフレクションでは、プライベートフィールドはgetDeclaredField()およびsetAccessible(true)を介してアクセスできます。Objectweb ASMバイトコードAPIを介して外部クラスのプライベートフィールドにアクセスするにはどうすればよいですか?のようなものからプライベートフィールドを取得するように設定しました

Field current = sourceObject.getDeclaredField(privateFieldName);
Field.setAccessible(true);
Type sourceType = Type.getType(sourceObject.getClass());
mv.visitFieldInsn(Opcodes.GETFIELD,
                  sourceType.getInternalName(),
                  privateFieldname,
                  Type.getDescriptor(current.getType()));

バイトコードを実行してプライベートフィールドを取得すると、常にエラー「java.lang.IllegalAccessError」が発生しました。

どんな手掛かり?バンドルに感謝します、

4

2 に答える 2

3

そんなことはできません。はsetAccessible(true)、プログラムの現在の実行における現在のフィールド参照にのみ影響します (つまり、変更された結果のプログラムの実行には影響しません)。

変更したプログラムを実行するときにプライベート フィールドにアクセスするには、基本的に、対応するリフレクション ステップをプログラムに埋め込む必要があります。

YourClass.thePrivatefieldローカル変数に格納されているオブジェクトのプライベート フィールドにアクセスするには、varId次のようにします。

// Get hold of the field-reference
mv.visitLdcInsn(Type.getType("LYourClass;"));
mv.visitLdcInsn("thePrivateField");
mv.visitMethodInsn(INVOKEVIRTUAL,
                   "java/lang/Class",
                   "getDeclaredField",
                   "(Ljava/lang/String;)Ljava/lang/reflect/Field;");

// Duplicate the reference
mv.visitInsn(DUP);

// Call setAccessible(true) using the first reference.
mv.visitInsn(ICONST_1);
mv.visitMethodInsn(INVOKEVIRTUAL,
                   "java/lang/reflect/Field",
                   "setAccessible",
                   "(Z)V");

// Call get(yourObject) using the second reference to the field.
mv.visitInsn(ALOAD, varId);
mv.visitMethodInsn(INVOKEVIRTUAL,
                   "java/lang/reflect/Field",
                   "get",
                   "(Ljava/lang/Object;)Ljava/lang/Object;");

アクセス可能にしようとしているフィールドが、書き換える cobe ベースの一部である場合は、ACC_PUBLIC代わりにACC_PRIVATE.

于 2010-10-01T13:31:13.510 に答える
0

実際の問題は、これらの変数に合法的にアクセスできないことです。これは、Java が内部クラスを持つ前に JVM がそのアクセス規則を定義したためです。そのため、javac は、JVM では合法的にアクセスできないが Java では可能なフィールドの合成アクセサーを作成します。例えば、

class Sample {
    private int i = 0;
    class Inner {
        int foo = i;
    }
}

次にjavap、生成されたクラスを逆コンパイルするために使用できます。

fowles@morbo:/tmp$ javap -private Sample
Compiled from "Sample.java"
class Sample extends java.lang.Object{
    private int i;
    Sample();
    static int access$000(Sample);
}

fowles@morbo:/tmp$ javap -c Sample.Inner
Compiled from "Sample.java"
class Sample$Inner extends java.lang.Object{
int foo;

final Sample this$0;

Sample$Inner(Sample);
  Code:
   0:   aload_0
   1:   aload_1
   2:   putfield    #1; //Field this$0:LSample;
   5:   aload_0
   6:   invokespecial   #2; //Method java/lang/Object."<init>":()V
   9:   aload_0
   10:  aload_0
   11:  getfield    #1; //Field this$0:LSample;
   14:  invokestatic    #3; //Method Sample.access$000:(LSample;)I
   17:  putfield    #4; //Field foo:I
   20:  return

}

で生成され、から使用されるaccess$000(Sample)メソッドに注意してください。悲しいことに、あなたの選択肢は次のいずれかですSampleSample.Inner

  1. フィールドをアクセシブルにする
  2. 反射を使用する
  3. 合成アクセサーを生成する
于 2011-03-16T17:11:34.057 に答える