1. Введение
Kotlin - это язык программирования для JVM, который компилируется непосредственно в байт-код Java. Однако он намного более лаконичен, чем Java, и некоторые функции JVM напрямую не вписываются в язык.
Вместо этого Kotlin предоставляет набор аннотаций, которые мы можем применить к нашему коду для запуска этих функций. Все это существует в пакете kotlin.jvm в kotlin-stdlib.
Одной из наиболее эзотерических из них является аннотация @JvmSynthetic.
2. Что делает @JvmSynthetic?
Эта аннотация применима к методам, полям, получателям и установщикам, и она помечает соответствующий элемент как синтетический в сгенерированном файле класса.
Мы можем использовать эту аннотацию в нашем коде точно так же, как и любую другую аннотацию:
@JvmSynthetic
val syntheticField: String = "Field"
var syntheticAccessor: String
@JvmSynthetic
get() = "Accessor"
@JvmSynthetic
set(value) {
}
@JvmSynthetic
fun syntheticMethod() {
}
Когда приведенный выше код скомпилирован, компилятор присваивает атрибут ACC_SYNTHETIC соответствующим элементам в файле class:
private final java.lang.String syntheticField;
descriptor: Ljava/lang/String;
flags: ACC_PRIVATE, ACC_FINAL, ACC_SYNTHETIC
ConstantValue: String Field
RuntimeInvisibleAnnotations:
0: #9()
public final void syntheticMethod();
descriptor: ()V
flags: ACC_PUBLIC, ACC_FINAL, ACC_SYNTHETIC
Code:
stack=0, locals=1, args_size=1
0: return
LocalVariableTable:
Start Length Slot Name Signature
0 1 0 this Lcom/baeldung/kotlin/SyntheticTest;
LineNumberTable:
line 20: 0
3. Что такое синтетический атрибут?
Атрибут ACC_SYNTHETIC предназначен байт-кодом JVM для указания на то, что элемент на самом деле не присутствовал в исходном коде, а был сгенерирован компилятором.
Его первоначальным намерением была поддержка вложенных классов и интерфейсов в Java 1.1, но теперь мы можем применить его к любым элементам, для которых он может нам понадобиться.
Любой элемент, который компилятор помечает как синтетический, будет недоступен из языка Java. Это включает в себя то, что они не отображаются ни в одном из инструментов, таких как наша IDE. Однако наш код на Kotlin не имеет таких ограничений и может прекрасно видеть эти элементы и получать к ним доступ.
Обратите внимание, что если у нас есть поле Kotlin, помеченное @JvmSynthetic, но не помеченное @JvmField, то сгенерированные getter и setter не считаются синтетическими методами и могут быть доступны без проблем.
Мы можем получить доступ к синтетическим элементам из Java с помощью Reflection API, если сможем найти их — например, по имени:
Method syntheticMethod = SyntheticClass.class.getMethod("syntheticMethod");
syntheticMethod.invoke(syntheticClass);
4. Для Чего Я Могу Это Использовать?
Единственными реальными преимуществами этого являются скрытие кода от Java-разработчиков и инструментов, а также информирование других разработчиков о состоянии кода. Он предназначен для работы на гораздо более низком уровне, чем код большинства обычных приложений.
Целью этого является поддержка генерации кода, позволяющая компилятору генерировать поля и методы, которые не должны быть доступны другим разработчикам, но которые необходимы для поддержки фактического открытого интерфейса. Мы можем рассматривать это как уровень защиты, выходящий за рамки частного или внутреннего.
В качестве альтернативы мы можем использовать его для скрытия кода от других инструментов, таких как code coverage или статический анализ.
Однако нет гарантии, что какой-либо данный инструмент будет использовать этот флаг, поэтому он не всегда может быть полезен в данном случае.
5. Заключение
Аннотация @JvmSynthetic, возможно, и не самый полезный инструмент из доступных, но, как мы уже видели, в определенных ситуациях он пригодится.
Как всегда, даже если мы используем его крайне редко, другой инструмент, доступный в вашем наборе инструментов разработчика, может оказаться весьма полезным. Когда придет время, когда у вас возникнет потребность в этом инструменте, стоит узнать, как он работает.
Оригинал статьи: https://www.baeldung.com/kotlin/jvm-synthetic