Синтетический класс на Java

143

Что такое синтетический класс в Java? Зачем его использовать? Как я могу использовать это?

andHapp
источник
1
Все ответы «не в вашем коде» устарели в Java 8, поскольку лямбда-выражения могут быть реализованы как синтетические (не анонимные) классы.
OrangeDog
Чтобы быть справедливым, лямбда все еще не "строго" класс, определенный явно в вашем коде. Таким образом, «не в вашем коде» остается в силе. Компилятор генерирует синтетические классы для вас без явного определения в вашем коде.
ManoDestra

Ответы:

15

Например, когда у вас есть оператор switch, java создает переменную, которая начинается с $. Если вы хотите увидеть пример этого, загляните в java-отражение класса, в котором есть оператор switch. Вы увидите эти переменные, когда у вас есть хотя бы один оператор switch в любом месте класса.

Чтобы ответить на ваш вопрос, я не верю, что вы можете получить доступ (кроме рефлексии) к синтетическим классам.

Если вы анализируете класс, о котором ничего не знаете (с помощью рефлексии) и вам нужно знать очень специфические и низкоуровневые вещи об этом классе, вы можете использовать методы отражения Java, которые имеют отношение к синтетическим классам. Единственное «использование» здесь - это получить больше информации о классе, чтобы правильно использовать его в своем коде.

(Если вы делаете это, вы, вероятно, создаете какую-то структуру, которую могли бы использовать другие разработчики.)

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

Милхаус
источник
1
Да, пример кода был бы хорош, если бы вы могли привести пример /
нанофарад
36
Это не отвечает на вопрос.
Дауд ибн Карим
Для случая переключателя я не уверен, происходит ли это для каждого переключателя, но я наблюдал это для переключателя с перечислениями; компилятор генерирует анонимный класс с одним статическим полем, которое обеспечивает отображение Enum.ordinal () -> 1, 2, 3 ... (то есть последовательность без пробелов), а затем инструкция lookupswitch запускает переключение в этой последовательности, а не напрямую по порядковым номерам.
Радим Ванса
106

Java имеет возможность создавать классы во время выполнения. Эти классы известны как синтетические классы или динамические прокси.

См. Http://java.sun.com/j2se/1.5.0/docs/guide/reflection/proxy.html для получения дополнительной информации.

Другие библиотеки с открытым исходным кодом, такие как CGLIB и ASM, также позволяют создавать синтетические классы и являются более мощными, чем библиотеки, поставляемые с JRE.

Синтетические классы используются библиотеками AOP (Aspect Oriented Programming), такими как Spring AOP и AspectJ, а также библиотеками ORM, такими как Hibernate.

Эндрю Ньюдигейт
источник
6
Динамические прокси не являются синтетическими классами. Доказательство:Proxy.newProxyInstance(Runnable.class.getClassLoader(), new Class[]{Runnable.class}, (proxy, method, args1) -> null).getClass().isSynthetic() == false
Miha_x64
3
Javadoc для java.lang.reflect.Member#isSyntheticговорит: Возвращает истину, если этот элемент был введен компилятором; в противном случае возвращает false
Гийом
Я считаю, что Javadoc для не java.lang.reflect.Member#isSyntheticимеет отношения к первоначальному вопросу. Члены - это поля, конструкторы и методы. Первоначальный вопрос был о синтетических классах , а не о синтетических членах. В Java 8 лямбда-выражения порождают синтетические классы - я не уверен, при каких других обстоятельствах они могут возникнуть.
Отец Джереми Криг
54

Ну я нашел ответ на первый вопрос в Google:

Класс может быть помечен как синтетический, если он генерируется компилятором, то есть он не отображается в исходном коде.

Это просто базовое определение, но я нашел его в ветке форума, и не было никакого объяснения. Все еще в поисках лучшего ...

andHapp
источник
15

синтетические классы / методы / поля:

Эти вещи важны для ВМ. Взгляните на следующий фрагмент кода:

class MyOuter {

  private MyInner inner;

  void createInner() {
    // The Compiler has to create a synthetic method
    // to construct a new MyInner because the constructor
    // is private.
    // --> synthetic "constructor" method
    inner = new MyInner();

    // The Compiler has to create a synthetic method
    // to doSomething on MyInner object because this
    // method is private.
    // --> synthetic "doSomething" method
    inner.doSomething();
  }

  private class MyInner {
    // the inner class holds a syntetic ref_pointer to
    // the outer "parent" class
    // --> synthetic field
    private MyInner() {
    }
    private void doSomething() {
    }
  }
}
Vinay W
источник
2
@CiroSantilli, 2016 г., нет, только синтетические методы доступа.
Miha_x64
8

Согласно этой дискуссии , хотя спецификация языка описывает свойство isSynthetic для классов, это в значительной степени игнорируется реализациями и не используется ни для динамических прокси, ни для анонимных классов. Синтетические поля и конструкторы используются для реализации вложенных классов (понятие вложенных классов отсутствует в байт-коде, только в исходном коде).

Я думаю, что концепция синтетических классов просто оказалась бесполезной, то есть никого не интересует, является ли класс синтетическим. С полями и методами это, вероятно, используется точно в одном месте: чтобы определить, что показывать в представлении структуры класса IDE - вы хотите, чтобы там отображались обычные методы и поля, но не синтетические, используемые для имитации вложенных классов. OTOH, вы действительно хотите анонимные классы, чтобы показать там.

Майкл Боргвардт
источник
@OrangeDog: да, это то, что я написал.
Майкл Боргвардт
Этот ответ, кажется, устарел, поскольку в Java 8 - лямбда-ссылки и методы используют эту функцию. Я добавил ответ, демонстрирующий это
Халк
7

Они создаются JVM во время выполнения, когда они вызывают закрытые члены внутреннего класса для целей отладки.

Методы, поля, класс, созданные JVM во время выполнения для его выполнения, называются синтетическими.

http://www.javaworld.com/article/2073578/java-s-synthetic-methods.html

http://javapapers.com/core-java/java-synthetic-class-method-field/

sathis
источник
Я предполагаю, что вы имеете в виду во время компиляции, а не во время выполнения.
Мостовский Свернуть
@sathis, ты имел ввиду javac, а не JVM?
Miha_x64
3

Также Синтетические Классы или Динамические Прокси используются EasyMock для создания реализаций интерфейсов или абстрактных классов во время выполнения.

http://www.easymock.org/

user2427
источник
2

Когда компилятор Java компилирует определенные конструкции, такие как внутренние классы, он создает синтетические конструкции ; это классы, методы, поля и другие конструкции, которые не имеют соответствующей конструкции в исходном коде.
Использование: Синтетические конструкции позволяют компиляторам Java реализовывать новые функции языка Java без изменений в JVM. Однако синтетические конструкции могут различаться в разных реализациях компилятора Java, а это означает, что файлы .class также могут различаться в разных реализациях.
ссылка: docs.oracle.com

анаварас ламуреп
источник
2

Как уже указывалось в различных ответах, компилятору разрешено генерировать различные конструкции (включая классы), которые не соответствуют напрямую чему-либо в исходном коде. Они должны быть помечены как синтетические:

13,1. Форма двоичного файла

Бинарное представление для класса или интерфейса также должно содержать все следующее:
[...]
11. Конструкция, испускаемая компилятором Java, должна быть помечена как синтетическая, если она не соответствует конструкции, объявленной явно или неявно в исходном коде. если только выпущенная конструкция не является методом инициализации класса (JVMS §2.9).
[...]

Как отметил @Holger в комментарии к другому вопросу, уместными примерами таких конструкций являются объекты Class, представляющие ссылки на методы и лямбда-выражения:

System.out.println(((Runnable) System.out::println).getClass().isSynthetic());
System.out.println(((Runnable) () -> {}).getClass().isSynthetic());

Вывод:

true
true

Хотя это прямо не упоминается, это следует из 15.27.4. Оценка лямбда-выражений во время выполнения :

Значение лямбда-выражения является ссылкой на экземпляр класса со следующими свойствами: [...]

и почти идентичная формулировка для ссылок на методы ( 15.13.3. Оценка ссылок на методы во время выполнения) ).

Поскольку этот класс явно не упоминается нигде в исходном коде, он должен быть синтетическим.

килектор
источник
1

Если я правильно понял, синтетический класс генерируется на лету, без необходимости давать ему явное имя. Например:

//...
Thread myThread = new Thread() {
         public void run() {
           // do something ...
         }
       };
myThread.start();
//...

Это создает синтетический подкласс Thread и переопределяет его метод run (), затем создает его экземпляр и запускает.

Иван
источник
3
я думал, что это был анонимный внутренний класс
Кумар Абхинав
2
Я должен согласиться с @KumarAbhinav. Не все анонимные внутренние классы являются синтетическими. Видеть: xinotes.net/notes/note/1339
bvdb
Анонимные внутренние классы не генерируют синтетические классы в Oracle JDK 1.8.0_45, они генерируют отдельные несинтетические классы с именами типа Outer$1.class.
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
1

Синтетический класс не появляется в вашем коде: он составлен компилятором. Например, метод моста, составленный компилятором в Java, обычно является синтетическим.

public class Pair<T> {
    private T first;
    private T second;
    public void setSecond(T newValue) {
        second = newValue;
    }
}


public class DateInterval extends Pair<String> {
    public void setSecond(String second) {
        System.out.println("OK sub");
    }

    public static void main(String[] args) throws NoSuchFieldException, SecurityException {
        DateInterval interval = new DateInterval();
        Pair pair = interval;
        pair.setSecond("string1");
    }
}

Используя команду javap -verbose DateInterval, вы можете увидеть метод моста:

public void setSecond(java.lang.Object);
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC

Это было составлено компилятором; это не появляется в вашем коде.

JavaFresher
источник
1

Что такое синтетический класс в Java?

syntheticКласс представляет собой .classфайл , созданный с помощью Java Compiler и не существует в исходном коде.

Пример использования syntheticкласса: Анонимный внутренний класс

  • java.text.DigitList $ 1 является syntheticклассом, и это внутренний анонимный класс внутри java.text.DigitList
  • И нет файла с исходным кодом с именем вроде, DigitList$1.javaно это внутренний файл вDigitList.java

Зачем его использовать?

Это механизм внутри логики компилятора Java для генерации .classфайла

Как я могу использовать это?

Нет, разработчики НЕ используют его напрямую.

Компилятор Java используют syntheticдля генерации .classфайла, а затем JVM читает .classфайл для выполнения логики программы.

Подробнее

  • Эта статья объясняет syntheticкласс в деталях
  • Эта ссылка перечисляет все syntheticвыходы класса в JDK
Счастливый
источник
статья очень полезна, спасибо
JasonMing
0

Синтетические конструкции - это классы, методы, поля и т. Д., Которые не имеют соответствующей конструкции в исходном коде. Синтетические конструкции позволяют компиляторам Java реализовывать новые функции языка Java без изменений в JVM. Однако синтетические конструкции могут различаться в разных реализациях компилятора Java, а это означает, что файлы .class также могут различаться в разных реализациях.

Ануп Диксит
источник
1
-1. Тот же самый текст, дословно, был опубликован в ответе, который был дан за год до вашего [ stackoverflow.com/a/24271953/1144395] , и, кроме того, в этом ответе дополнительно приводилась официальная ссылка на источник текста, и было предоставлено форматирование для более удобного чтения. , Пожалуйста, не жадно спамите вопросы с четко продублированными ответами.
Нака