Какой штраф за синтетические методы? - PullRequest
15 голосов
/ 06 апреля 2011

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

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

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

Ответы [ 2 ]

16 голосов
/ 06 апреля 2011

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 .

4 голосов
/ 06 апреля 2011

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...