Kotlin 中 `@JvmField` 注解的使用

一、先明确 @JvmField 的核心作用

@JvmField 是 Kotlin 提供的JVM 互操作性注解 ,它的核心功能是:让 Kotlin 中声明的 val(只读属性)或 var(可变属性),在编译为 Java 字节码时,直接生成一个 公共(public)的成员字段(Field),而不是默认生成「私有字段 + getter 方法(val 对应)/ getter+setter 方法(var 对应)」的封装形式

简单说,它会「跳过 Kotlin 属性的默认封装」,直接暴露原始的 Java 公共字段。

二、对比:有无 @JvmField 的编译差异

1. 不加 @JvmField(Kotlin 默认行为)

如果你写:

kotlin 复制代码
class ApiManager {
    // 无 @JvmField 注解
    val api = RetrofitCreate.create(ApiService::class.java)
}

编译为 Java 后,会生成私有字段 + 公共 getter 方法

java 复制代码
public class ApiManager {
    // 私有字段,外部无法直接访问
    private final ApiService api;

    public ApiManager() {
        this.api = RetrofitCreate.create(ApiService.class);
    }

    // 公共 getter 方法,外部通过 getApi() 获取值
    public ApiService getApi() {
        return this.api;
    }
}

此时在 Java 中访问,必须通过 apiManager.getApi(),无法直接 apiManager.api

2. 加 @JvmField(你的代码写法)

你的代码:

kotlin 复制代码
class ApiManager {
    @JvmField
    val api = RetrofitCreate.create(ApiService::class.java)
}

编译为 Java 后,会生成公共成员字段,无 getter 方法:

java 复制代码
public class ApiManager {
    // 公共字段,外部可直接访问(无 getter 方法)
    public final ApiService api;

    public ApiManager() {
        this.api = RetrofitCreate.create(ApiService.class);
    }
}

此时在 Java 中可直接通过 apiManager.api 访问该属性,无需调用 getter 方法。

三、@JvmField 的使用约束

  1. 仅适用于 val/var 属性:不能用于函数、参数等其他元素。
  2. 不能与 lateinit 以外的属性委托/特殊修饰符共存
    • 支持:@JvmField lateinit var api: ApiService(延迟初始化属性可搭配)
    • 不支持:@JvmField val api by lazy { ... }(属性委托无法搭配,因为委托依赖 Kotlin 内部封装逻辑)
  3. val 修饰的 @JvmField 字段,编译后为 final(只读) :和你的代码一致,Java 中无法修改该字段的值;若用 var 修饰,则编译后为非 final(可修改)。
  4. 通常用于类成员属性 :可用于顶层属性(文件级属性),编译后会成为对应文件名的 Kt 类的公共静态字段。

四、使用 @JvmField 的核心场景

你的代码使用 @JvmField,大概率是为了Kotlin 与 Java 的互操作性 ------当你的 Kotlin 代码需要被 Java 代码调用时,通过 @JvmField 可以让 Java 侧像访问普通 Java 公共字段一样,直接访问 Kotlin 属性,简化代码写法(无需频繁调用 getXxx() 方法)。

除此之外,在一些需要反射访问字段、或与老的 Java 框架(依赖公共字段注入)集成时,@JvmField 也必不可少(因为反射获取 getter 方法和直接获取字段的逻辑不同,框架若要求直接访问字段,则必须用 @JvmField)。

总结

  1. @JvmField 核心:让 Kotlin 属性编译为 Java 公共字段,跳过默认的「私有字段 + getter/setter」封装。
  2. 你的代码效果:api 会成为公共只读(final)字段,Java 可直接 对象.api 访问。
  3. 关键差异:有无 @JvmField 决定了 Java 侧是「调用 getter」还是「直接访问字段」。
  4. 使用约束:不支持属性委托(如 lazy),仅适用于 val/varval 对应 Java final 字段。
相关推荐
iFeng的小屋1 天前
【2026最新当当网爬虫分享】用Python爬取千本日本相关图书,自动分析价格分布!
开发语言·爬虫·python
yugi9878381 天前
基于MATLAB的一键式EMD、EEMD、CEEMD和SSA信号去噪实现
开发语言·matlab·信号去噪
似霰1 天前
Linux timerfd 的基本使用
android·linux·c++
热爱编程的小刘1 天前
Lesson05&6 --- C&C++内存管理&模板初阶
开发语言·c++
qq_12498707531 天前
基于Java Web的城市花园小区维修管理系统的设计与实现(源码+论文+部署+安装)
java·开发语言·前端·spring boot·spring·毕业设计·计算机毕业设计
froginwe111 天前
Python 条件语句
开发语言
七夜zippoe1 天前
Python统计分析实战:从描述统计到假设检验的完整指南
开发语言·python·统计分析·置信区间·概率分布
2601_949146531 天前
Python语音通知API示例代码汇总:基于Requests库的语音接口调用实战
开发语言·python
3GPP仿真实验室1 天前
【Matlab源码】6G候选波形:OFDM-IM 索引调制仿真平台
开发语言·matlab
darling3311 天前
mysql 自动备份以及远程传输脚本,异地备份
android·数据库·mysql·adb