Ответ 1
Eclipse предупреждает вас о том, что вы можете раскрывать информацию, которую считаете конфиденциальной. Синтетические средства доступа могут быть использованы вредоносным кодом, как показано ниже.
Если ваш код должен работать в защищенной виртуальной машине, может быть неразумно использовать внутренние классы. Если вы можете использовать рефлексию и иметь полный доступ ко всему, синтетические средства доступа вряд ли будут измеримы.
Например, рассмотрим этот класс:
public class Foo {
private Object baz = "Hello";
private class Bar {
private Bar() {
System.out.println(baz);
}
}
}
Подпись для Foo
на самом деле:
public class Foo extends java.lang.Object{
public Foo();
static java.lang.Object access$000(Foo);
}
access$000
генерируется автоматически, чтобы позволить отдельному классу Bar
доступ к baz
и будет помечен атрибутом Synthetic. Сгенерированные точные имена зависят от реализации. Обычные компиляторы не позволят вам скомпилировать этот метод, но вы можете создавать свои собственные классы, используя ASM (или аналогичный), например так:
import org.objectweb.asm.*;
public class FooSpyMaker implements Opcodes {
public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0);
cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "Spy", null, "java/lang/Object",null);
MethodVisitor ctor = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
ctor.visitCode();
ctor.visitVarInsn(ALOAD, 0);
ctor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
ctor.visitInsn(RETURN);
ctor.visitMaxs(1, 1);
ctor.visitEnd();
MethodVisitor getBaz = cw.visitMethod(ACC_PUBLIC, "getBaz",
"(LFoo;)Ljava/lang/Object;", null, null);
getBaz.visitCode();
getBaz.visitVarInsn(ALOAD, 1);
getBaz.visitMethodInsn(INVOKESTATIC, "Foo", "access$000",
"(LFoo;)Ljava/lang/Object;");
getBaz.visitInsn(ARETURN);
getBaz.visitMaxs(1, 2);
getBaz.visitEnd();
cw.visitEnd();
return cw.toByteArray();
}
}
Это создает простой класс Spy
, который позволит вам вызывать access$000
:
public class Spy extends java.lang.Object{
public Spy();
public java.lang.Object getBaz(Foo);
}
Используя это, вы можете проверить значение baz
без каких-либо размышлений или каким-либо другим способом.
public class Test {
public static void main(String[] args) {
Foo foo = new Foo();
Spy spy = new Spy();
System.out.println(spy.getBaz(foo));
}
}
Реализация Spy
требует, чтобы он был в том же пакете, что и Foo
и чтобы Foo
не был в запечатанном JAR.