@JvmSynthetic 在 Kotlin 中的预期用途是什么?

What's the intended use of @JvmSynthetic in Kotlin?

我在 kotlin-stdlib 中遇到了 @JvmSynthetic 注释,我想知道它的用途,但不幸的是,它没有记录。 (UPD:就是那一刻)

据我了解,将其应用于程序元素会将 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

从非 Kotlin 来源隐藏声明是否是对 @JvmSynthetic 的有效使用?它是预期用途吗?其他合适的用例是什么?

由于 @JvmSynthetic 对 Java 隐藏了函数,它们也不能在 Java 中被覆盖(当涉及到 abstract 成员时,调用会导致AbstractMethodError)。鉴于此,我可以使用 @JvmSynthetic 来禁止覆盖 Java 来源中 Kotlin class 的成员吗?

在普通的 Java 中,synthetic 方法由 javac 编译器生成。通常编译器必须在嵌套的 classes 上创建合成方法,当用 private 修饰符指定的字段被封闭的 class.

访问时

在 java 中给出以下 class:

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 class 访问 nested.syntheticString 字段时,它确实调用了编译器生成的静态 synthetic 方法(名称类似于 access0).

即使 Kotlin 公开了能够 "force" 创建合成方法的 @JvmSynthetic 注释,我建议不要在普通 "user" 代码中使用它。合成方法是编译器的低级技巧,我们不应该在日常代码中依赖这些东西。我认为它可以支持标准库的其他部分,但如果您好奇的话,您应该直接询问 JetBrains 人员(试试官方 Kotlin Discussion Forum

首先要回答究竟是什么合成方法,让我们看看Java language specification:

11. A construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared explicitly or implicitly in source code, unless the emitted construct is a class initialization method (JVMS §2.9).

@JvmSynthetic 注释正是这样做的:防止从源代码访问。该方法仍然会出现在反射中,然后被标记为合成的。

更准确地说,来自 the Kotlin documentation(强调我的):

@JvmSynthetic

Sets ACC_SYNTHETIC flag on the annotated target in the Java bytecode.

Synthetic targets become inaccessible for Java sources at compile time while still being accessible for Kotlin sources. Marking target as synthetic is a binary compatible change, already compiled Java code will be able to access such target.

This annotation is intended for rare cases when API designer needs to hide Kotlin-specific target from Java API while keeping it a part of Kotlin API so the resulting API is idiomatic for both.

如上一段所述,@JvmSynthetic 是一种用于 API 设计的工具,它可以让库编写者避免自动生成 Java 等价物。最流行的用例可能是 Kotlin 独有的功能,例如运算符重载、componentN() 方法或属性,它们可能有更惯用的方式在 Java.

中公开

值得注意的是,此注释的目标是 属性 setters/getters、函数和字段——基本上所有在 Java 中转换为方法的内容。

@Target([
    AnnotationTarget.FUNCTION,
    AnnotationTarget.PROPERTY_GETTER,
    AnnotationTarget.PROPERTY_SETTER,
    AnnotationTarget.FIELD])
annotation actual class JvmSynthetic