Какое наказание за синтетические методы?

При разработке приложения Java в Eclipse я получил предупреждение о "методе/ценности, доступном через синтетический метод". Решение просто изменило модификатор частного доступа на уровень по умолчанию.

Это заставило меня задуматься: какое наказание за использование синтетического метода? Есть некоторая? Я предполагаю, что компилятор /Eclipse вызывает предупреждение, но это что-то настолько релевантное или что-то, что можно было бы безопасно игнорировать?

Я не видел эту информацию здесь, поэтому я прошу.

Ответы

Ответ 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.

Ответ 2

Я уверен, что штраф является не чем иным, как дополнительным вызовом метода. Другими словами, совершенно не имеет значения практически для всех случаев использования.

Если это особенно горячий путь, вы можете беспокоиться, но вы должны установить с помощью профилировщика, что это на самом деле ваша проблема.

Я просто выключу предупреждение.