1. 简介

Kotlin 是一种运行在 JVM 上的语言,它最终会被编译成 Java 字节码。虽然 Kotlin 在语法上比 Java 更加简洁,但某些 JVM 原生特性并不能很好地融入 Kotlin 的语法体系中。

为此,Kotlin 提供了一系列注解(annotation),用于触发这些 JVM 特性,这些注解都位于 kotlin.jvm 包下,是 kotlin-stdlib 的一部分。

其中,@JvmSynthetic 是一个相对冷门但用途明确的注解。

2. @JvmSynthetic 的作用

该注解可以用于方法、字段、getter 和 setter,其作用是在生成的字节码中将对应的元素标记为 synthetic(合成)

使用方式和其他注解一样简单:

@JvmSynthetic
val syntheticField: String = "Field"

var syntheticAccessor: String
  @JvmSynthetic
  get() = "Accessor"
  
  @JvmSynthetic
  set(value) {
  }

@JvmSynthetic
fun syntheticMethod() {
}

编译后,这些元素在字节码中会带上 ACC_SYNTHETIC 标志,例如:

private final java.lang.String syntheticField;
  descriptor: Ljava/lang/String;
  flags: ACC_PRIVATE, ACC_FINAL, ACC_SYNTHETIC
  ConstantValue: String Field
  RuntimeInvisibleAnnotations:
    0: #9()

public final void syntheticMethod();
  descriptor: ()V
  flags: ACC_PUBLIC, ACC_FINAL, ACC_SYNTHETIC
  Code:
    stack=0, locals=1, args_size=1
       0: return
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       1     0  this   Lcom/baeldung/kotlin/SyntheticTest;
    LineNumberTable:
      line 20: 0

3. 什么是 Synthetic 属性?

JVM 字节码中的 ACC_SYNTHETIC 标志表示该元素并非原始源码中定义的内容,而是由编译器生成的。

最初这个标志是为 Java 1.1 中支持嵌套类和接口而设计的。如今,我们可以将它用于任何需要隐藏的编译器生成元素。

关键点: 被标记为 synthetic 的元素,在 Java 中是不可见的,包括 IDE 工具也不会显示它们。但在 Kotlin 中则完全不受影响,可以正常访问。

⚠️ 注意: 如果一个 Kotlin 字段被 @JvmSynthetic 注解标记,但没有加上 @JvmField,那么它的 getter 和 setter 方法并不会被标记为 synthetic,因此仍然可以通过 Java 访问。

我们也可以通过 Java 的反射机制访问这些 synthetic 元素:

Method syntheticMethod = SyntheticClass.class.getMethod("syntheticMethod");
syntheticMethod.invoke(syntheticClass);

4. 使用场景

@JvmSynthetic 的主要用途有以下几点:

  • 对 Java 隐藏实现细节:适用于需要隐藏的内部字段或方法,避免被 Java 调用或暴露在 IDE 中。
  • 作为开发提示:表明该元素是编译器生成的,不建议直接使用。
  • 辅助代码生成:在编译期生成的中间代码或辅助字段,不希望暴露给外部使用。
  • ⚠️ 绕过工具检查:例如代码覆盖率工具或静态分析工具可能会忽略 synthetic 元素,但不能保证所有工具都支持。

需要注意的是,它并不是一种访问控制机制,更像是一个“标记”,用于辅助编译和工具处理。

5. 小结

虽然 @JvmSynthetic 不是日常开发中常用的注解,但它在特定场景下非常有用:

  • 隐藏编译器生成的代码
  • 控制 Java 对 Kotlin 生成代码的可见性
  • 辅助构建更干净的 API 接口

对于 Kotlin 开发者来说,了解这个注解有助于更好地理解 Kotlin 与 JVM 的交互机制,也能在需要时更灵活地控制生成的字节码结构。在进行底层库开发或代码生成工具开发时,尤其值得考虑使用。


原始标题:The @JvmSynthetic Annotation in Kotlin