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

2022-09-02 04:25:15

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

据我所知,将其应用于程序元素会将修饰符添加到相应的字节码元素中。因此,该元素在 Java 中变得不可见:synthetic

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

由于从Java中隐藏了函数,因此它们也不能在Java中被覆盖(并且当涉及到成员时,调用结果为)。鉴于此,我是否可以禁止在 Java 源代码中重写 Kotlin 类的成员?@JvmSyntheticabstractAbstractMethodError@JvmSynthetic


答案 1

在普通Java中,方法由编译器生成。通常,当封闭类访问使用私有修饰符指定的字段时,编译器必须在嵌套类上创建综合方法。syntheticjavac

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

当类访问该字段时,它确实在调用编译器生成的静态方法(命名为类似 )。SyntheticSamplenested.syntheticStringsyntheticaccess$100

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


答案 2

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

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

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

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

@JvmSynthetic

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

合成目标在编译时对于 Java 源代码变得不可访问,而对于 Kotlin 源代码仍然可访问。将目标标记为合成是一个二进制兼容的更改,已经编译的Java代码将能够访问这样的目标。

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

如上一段所述,是一个用于API设计的工具,它使库编写器可以避免自动生成Java等效项。可能最流行的用例是仅限Kotlin的功能,例如运算符重载,方法或属性,它们可能具有在Java中公开的更惯用方式。@JvmSyntheticcomponentN()

值得注意的是,这个注释的目标是属性 setter/getters、函数和字段 ——基本上都是在 Java 中转换为方法的东西。

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

推荐