Аннотация @JvmSynthetic в Котлине

@JvmSynthetic Annotation в Котлине

1. Вступление

Kotlin is a programming language for the JVM and compiles directly to Java Bytecode. Однако он намного лаконичнее, чем Java, и некоторые функции JVM не вписываются непосредственно в язык.

Вместо этогоKotlin provides a set of annotations that we can apply to our code to trigger these features. Все они находятся в пакетеkotlin.jvm вkotlin-stdlib.

Одной из наиболее эзотерических из них является аннотация@JvmSynthetic.

2. Что делает@JvmSynthetic?

Эта аннотация применима к методам, полям, геттерам и сеттерам - и этоmarks the appropriate element as synthetic in the generated class file.

Мы можем использовать эту аннотацию в нашем коде точно так же, как любую другую аннотацию:

@JvmSynthetic
val syntheticField: String = "Field"

var syntheticAccessor: String
  @JvmSynthetic
  get() = "Accessor"

  @JvmSynthetic
  set(value) {
  }

@JvmSynthetic
fun syntheticMethod() {
}

Когда приведенный выше код компилируется,the compiler assigns the ACC_SYNTHETIC attribute to the corresponding elements in the class file:

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/example/kotlin/SyntheticTest;
    LineNumberTable:
      line 20: 0

3. Что такое синтетический атрибут?

The ACC_SYNTHETIC attribute is intended by the JVM Bytecode to indicate that an element wasn’t actually present in the original source code, но вместо этого был сгенерирован компилятором.

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

Any element that the compiler marks as synthetic will be inaccessible from the Java language. Это включает в себя невидимость ни в одном инструменте, например в нашей IDE. Тем не менее, наш код Kotlin не имеет таких ограничений и может прекрасно видеть и получать доступ к этим элементам.

Обратите внимание, что если у нас есть поле Kotlin, аннотированное@JvmSynthetic, но не аннотированное@JvmField,, тогда сгенерированные геттер и сеттер не считаются синтетическими методами и могут быть легко доступны.

Мы можем получить доступ к синтетическим элементам из Java с помощью Reflection API, если сможем их найти, например, по имени:

Method syntheticMethod = SyntheticClass.class.getMethod("syntheticMethod");
syntheticMethod.invoke(syntheticClass);

4. Для чего я могу это использовать?

Единственным реальным преимуществом этого является сокрытие кода от разработчиков и инструментов Java, а также как указание другим разработчикам о состоянии кода. It’s intended for working at a much lower level than most typical application code.

The intention of it is to support code generation, позволяя компилятору генерировать поля и методы, которые не должны быть открыты другим разработчикам, но необходимы для поддержки реального открытого интерфейса. Мы можем думать об этом как об уровне защиты, превышающемprivate илиinternal.

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

Однако нет никакой гарантии, что какой-либо конкретный инструмент будет учитывать этот флаг, поэтому он не всегда может быть здесь полезен.

5. Заключение

Аннотация@JvmSynthetic, возможно, не самый полезный доступный инструмент, но, как мы видели здесь, ее можно использовать в определенных ситуациях.

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