Какой штраф за синтетические методы?

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

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

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

2 ответа

Решение

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 и будет помечен синтетическим атрибутом. Сгенерированные точные имена зависят от реализации. Обычные компиляторы не позволят вам скомпилировать этот метод, но вы можете создавать свои собственные классы, используя 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 не в запечатанном банке.

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

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

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

Другие вопросы по тегам