21

@JvmSynthetic我在 kotlin-stdlib 中遇到过注释,我想知道它的用途,但不幸的是,它没有记录。(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 类的成员吗?

4

2 回答 2

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!";
    }
}

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

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

于 2016-12-07T18:53:53.510 回答
7

首先,要回答合成方法到底是什么让我们看一下Java 语言规范

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

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

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

@JvmSynthetic

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

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
于 2018-09-19T13:05:53.037 回答