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

hot*_*key 18 java java-interop synthetic kotlin

@JvmSynthetic在kotlin-stdlib中遇到了注释,我想知道它是什么,但不幸的是,它没有记录.

据我所知,将它应用于程序元素会将synthetic修饰符添加到相应的字节码元素.结果,该元素从Java变得不可见:

class MyClass {
    @JvmSynthetic
    fun f() { }
}
Run Code Online (Sandbox Code Playgroud)

Java代码中的某处:

MyClass c = new MyClass();
c.f() // Error: cannot resolve method f()
Run Code Online (Sandbox Code Playgroud)

但是在Kotlin代码中仍然可以看到相同的元素:

val c = MyClass()
c.f() // OK
Run Code Online (Sandbox Code Playgroud)

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

由于@JvmSynthetic隐藏了来自Java的函数,它们也无法在Java中被覆盖(当涉及abstract成员时,调用会产生AbstractMethodError).鉴于此,我可以@JvmSynthetic用来禁止在Java源代码中覆盖Kotlin类的成员吗?

小智 12

在普通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!";
    }
}
Run Code Online (Sandbox Code Playgroud)

SyntheticSample类访问该nested.syntheticString字段时,它确实调用了synthetic编译器生成的静态方法(类似名称access$100).

即使Kotlin公开了一个@JvmSynthetic能够"强制"创建合成方法的注释,我建议不要在普通的"用户"代码中使用它.合成方法是编译器制作的低级技巧,我们不应该在日常代码中依赖这些东西.我认为它可以支持标准库的其他部分,但如果你很好奇,你应该直接向JetBrains人询问(试试官方Kotlin论坛)

  • 好吧,我同意它看起来像一个需要小心处理的危险工具,但它仍然是`kotlin-stdlib`的一部分,它是一个公共API.这让我觉得普通开发人员(或者图书馆/工具开发人员)可能会遇到"@ JvmSynthetic"的用例.此外,`synthetic`方法更广泛地被`javac`用于嵌套类:至少用于覆盖具有不同签名的方法(包括用非泛化方法覆盖的泛型方法). (2认同)

The*_*tor 5

首先,要回答合成方法究竟什么,让我们来看看Java 语言规范

11.如果 Java 编译器发出的构造与源代码中显式或隐式声明的构造不对应,则必须将其标记为合成的,除非发出的构造是类初始化方法(JVMS §2.9)。

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

更准确地说,来自Kotlin 文档(重点是我的):

@JvmSynthetic

ACC_SYNTHETIC在 Java 字节码中的注释目标上设置标志。

在编译时,Java 源无法访问合成目标,而 Kotlin 源仍然可以访问。将目标标记为合成是二进制兼容的更改,已编译的 Java 代码将能够访问此类目标。

此注释适用于API 设计人员需要对 Java API 隐藏 Kotlin 特定目标,同时将其保留为 Kotlin API 的一部分的极少数情况,因此生成的 API 对两者都是惯用的。

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

值得注意的是,这个注解的目标是属性设置器/获取器、函数和字段——基本上所有在 Java 中转换为方法的东西。

@Target([
    AnnotationTarget.FUNCTION,
    AnnotationTarget.PROPERTY_GETTER,
    AnnotationTarget.PROPERTY_SETTER,
    AnnotationTarget.FIELD])
annotation actual class JvmSynthetic
Run Code Online (Sandbox Code Playgroud)