Какова цель использования @JvmSynthetic в Kotlin?

Я сталкивался с @JvmSynthetic аннотации в kotlin-stdlib, и мне интересно, для чего она нужна, но, к сожалению, она недокументирована.

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

class MyClass {
    @JvmSynthetic
    fun f() { }
}

Где-то в коде Java:

MyClass c = new MyClass();
c.f() // Error: cannot resolve method f()

Но те же элементы все еще видны в коде Kotlin:

val c = MyClass()
c.f() // OK

Является ли сокрытие деклараций из не-котлинских источников допустимым использованием @JvmSynthetic? Это предполагаемое использование? Каковы другие подходящие варианты использования?

поскольку @JvmSynthetic скрывает функции от Java, они также не могут быть переопределены в Java (и когда дело доходит до abstract член, вызовы затем приводят к AbstractMethodError). Учитывая это, могу ли я использовать @JvmSynthetic запретить переопределение членов класса Kotlin в источниках Java?

2 ответа

В простой Java synthetic методы генерируются javac компилятор. Обычно компилятор должен создавать синтетические методы для вложенных классов, когда доступ к полям, указанным с помощью модификатора private, осуществляется включающим классом.

Учитывая следующий класс в Java:

public final class SyntheticSample
{
    public static void main(final String[] args)
    {
        SyntheticSample.Nested nested = new SyntheticSample.Nested();
        out.println("String: " + nested.syntheticString);
    }

    private static final class Nested
    {
        private String syntheticString = "I'll become a method!";
    }
}

когда SyntheticSample класс получает доступ к nested.syntheticString поле, это действительно вызывает статический synthetic метод, сгенерированный компилятором access$100).

Даже если Котлин выставляет @JvmSynthetic аннотацию, способную "форсировать" создание синтетических методов, советую не использовать ее в обычном "пользовательском" коде. Синтетические методы - это низкоуровневые уловки, сделанные компилятором, и мы никогда не должны полагаться на такие вещи в повседневном коде. Я думаю, что он там для поддержки других частей стандартной библиотеки, но вы должны спросить парней из JetBrains, если вам интересно (попробуйте на официальном дискуссионном форуме Kotlin)

Во-первых, чтобы ответить на вопрос, что такое синтетические методы, давайте взглянем на спецификацию языка Java:

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

@JvmSynthetic аннотация делает именно это: предотвращает доступ из исходного кода. Метод будет по-прежнему отображаться в отражении и затем будет помечен как синтетический.

Точнее, из документации Kotlin (выделено мое):

@JvmSynthetic

наборы ACC_SYNTHETIC пометить аннотированную цель в байт-коде Java.

Синтетические цели становятся недоступными для источников Java во время компиляции, но при этом остаются доступными для источников Kotlin. Маркировка цели как синтетической является бинарно-совместимым изменением, уже скомпилированный код Java сможет получить доступ к такой цели.

Эта аннотация предназначена для редких случаев, когда разработчику API необходимо скрыть конкретную цель Kotlin от Java API, оставляя ее частью API Kotlin, поэтому полученный API является идиоматическим для обоих.

Как описано в последнем абзаце, @JvmSynthetic это инструмент для разработки API, который позволяет разработчику библиотеки избегать автоматической генерации Java-эквивалентов. Вероятно, наиболее популярными вариантами использования являются только функции Kotlin, такие как перегрузка операторов, componentN() методы или свойства, которые могут иметь более идиоматический способ представления в Java.

Следует отметить, что целью этих аннотаций являются установщики / получатели свойств, функции и поля - в основном все, что переводится в Java в метод.

@Target([
    AnnotationTarget.FUNCTION,
    AnnotationTarget.PROPERTY_GETTER,
    AnnotationTarget.PROPERTY_SETTER,
    AnnotationTarget.FIELD])
annotation actual class JvmSynthetic
Другие вопросы по тегам