简体   繁体   English

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

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

I have come across the @JvmSynthetic annotation in kotlin-stdlib, and I'm wondering what it is for, but, unfortunately, it is undocumented. 我在kotlin-stdlib中遇到过@JvmSynthetic注释,我想知道它是什么,但不幸的是,它没有记录。 (UPD: it was at that moment) (UPD:就在那一刻)

As far as I understand, applying it to a program element will add the synthetic modifier to the corresponding bytecode elements. 据我所知,将它应用于程序元素将synthetic修饰符添加到相应的字节码元素。 As a consequence, the element becomes invisible from Java: 结果,该元素从Java变得不可见:

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

Somewhere in Java code: Java代码中的某处:

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

But the same elements are still visible in Kotlin code: 但是在Kotlin代码中仍然可以看到相同的元素:

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

Is hiding declarations from non-Kotlin sources a valid use of @JvmSynthetic ? 隐藏来自非Kotlin来源的声明是否有效使用@JvmSynthetic Is it the intended use? 它是预期用途吗? What are the other appropriate use cases? 其他适当的用例是什么?

Since @JvmSynthetic hides functions from Java, they cannot be overridden in Java either (and when it comes to an abstract member, the calls then result into AbstractMethodError ). 由于@JvmSynthetic隐藏了Java中的函数,因此它们也无法在Java中被覆盖(当涉及abstract成员时,调用会导致AbstractMethodError )。 Given that, can I use @JvmSynthetic to prohibit overriding members of a Kotlin class in Java sources? 鉴于此,我可以使用@JvmSynthetic来禁止在Java源代码中覆盖Kotlin类的成员吗?

In plain Java, synthetic methods are generated by the javac compiler. 在普通Java中, synthetic方法由javac编译器生成。 Normally the compiler must create synthetic methods on nested classes, when fields specified with the private modifier are accessed by the enclosing class. 通常,当封闭类访问使用private修饰符指定的字段时,编译器必须在嵌套类上创建合成方法。

Given the following class in java: 给出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!";
    }
}

when the SyntheticSample class accesses the nested.syntheticString field, it is indeed calling a static synthetic method generated by the compiler (named something like access$100 ). SyntheticSample类访问nested.syntheticString字段时,它确实调用了编译器生成的静态synthetic方法(名称类似于access$100 )。

Even if Kotlin exposes a @JvmSynthetic annotation that is able to "force" the creation of synthetic methods, I advice to not using it in normal "user" code. 即使Kotlin公开了一个能够“强制”创建合成方法的@JvmSynthetic注释,我建议不要在普通的“用户”代码中使用它。 Synthetic methods are low-level tricks made by the compiler, and we should never rely on such things in everyday code. 合成方法是编译器制作的低级技巧,我们不应该在日常代码中依赖这些东西。 I think it's there to support other parts of the standard library, but you should ask the JetBrains guys directly if you're curious (try on the official Kotlin Discussion Forum ) 我认为它可以支持标准库的其他部分,但如果你很好奇,你应该直接向JetBrains人询问(试试官方Kotlin论坛

First, to answer what synthetic methods actually are , let's have a look at the Java language specification : 首先,要回答什么合成方法实际上 ,让我们来看看Java语言规范

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

The @JvmSynthetic annotation does exactly that: prevent access from source code. @JvmSynthetic批注就是这样做的:阻止从源代码访问。 The method will still appear in reflection and is then marked as synthetic. 该方法仍将出现在反射中,然后标记为合成。

More precisely, from the Kotlin documentation (emphasis mine): 更确切地说,从Kotlin文档 (强调我的):

@JvmSynthetic

Sets ACC_SYNTHETIC flag on the annotated target in the Java bytecode. 在Java字节码中的带注释的目标上设置ACC_SYNTHETIC标志。

Synthetic targets become inaccessible for Java sources at compile time while still being accessible for Kotlin sources. 在编译时,Java源代码无法访问合成目标,而Kotlin源代码仍可访问。 Marking target as synthetic is a binary compatible change, already compiled Java code will be able to access such target. 将目标标记为合成是二进制兼容的更改,已编译的Java代码将能够访问此类目标。

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

As described in the last paragraph, @JvmSynthetic is a tool for API design, which lets a library writer avoid automatic generation of Java equivalents. 如上一段所述, @JvmSynthetic是一个API设计工具,它允许库@JvmSynthetic器避免自动生成Java等价物。 Probably the most popular use cases are Kotlin-only features, such as operator overloading, componentN() methods or properties, which may have a more idiomatic way to be exposed in Java. 可能最流行的用例是仅Kotlin的特性,例如运算符重载, componentN()方法或属性,这些特性可能在Java中暴露出更惯用的方式。

It is noteworthy that the target of this annotations are property setters/getters, functions and fields -- basically everything that translates in Java to a method. 值得注意的是,这个注释的目标是属性设置器/ getter,函数和字段 - 基本上所有用Java翻译成方法的东西。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM