如何实现Kotlin类DSL与Java Builder风格API的互相隔离?
完美的需求!这正是Kotlin/Java跨语言协作中兼顾双方开发习惯的典型场景,我来给你拆解实现方案和背后的注解原理:
核心思路
我们需要做两件核心事情:
- 让Kotlin的DSL专属属性对Java完全不可见
- 让Java的Builder风格方法对Kotlin完全不可见
具体实现代码
先上完整的MyClass实现,再逐一解释细节:
class MyClass { // Kotlin DSL专属属性:Java无法访问 @JvmSynthetic var offset: Int = 0 // Java Builder风格方法:Kotlin无法访问 @JvmName("withOffset") @Deprecated(message = "请在Kotlin中使用DSL语法", level = DeprecationLevel.HIDDEN) fun withOffsetForJava(value: Int): MyClass { this.offset = value return this } // Kotlin DSL入口 companion object { operator fun invoke(block: MyClass.() -> Unit): MyClass { return MyClass().apply(block) } } }
1. 隐藏Kotlin属性不让Java访问:@JvmSynthetic
@JvmSynthetic是Kotlin标准库提供的注解,标记后:
- Kotlin编译器会把该属性的getter/setter在字节码中标记为合成元素(synthetic)
- Java编译器会直接拒绝访问这些合成元素,不管是调用
setOffset()/getOffset(),还是直接访问offset字段都会编译报错 - 完全满足“Java无法访问Kotlin公开属性”的要求
2. 隐藏Builder方法不让Kotlin访问:@Deprecated(level = DeprecationLevel.HIDDEN)
为Java提供的withOffset方法我们做了两处处理:
@JvmName("withOffset"):强制Java中看到的方法名是withOffset,符合Builder风格的命名习惯@Deprecated(level = DeprecationLevel.HIDDEN):这是Kotlin专属的注解级别,标记后:- Kotlin编译器会完全隐藏该方法,既不会出现在自动补全中,也不允许代码调用(编译报错)
- Java完全不受影响,因为Java不识别这个Kotlin特有的废弃级别
验证效果
Kotlin中使用(仅DSL方式有效)
// 正常使用DSL,编译通过 val myObj = MyClass { offset = 1 } // 尝试调用Builder方法,编译报错(方法被隐藏) // myObj.withOffsetForJava(2) // 无法访问
Java中使用(仅Builder方式有效)
// 正常使用Builder链式调用,编译通过 MyClass myObj = new MyClass().withOffset(1); // 尝试调用自动生成的setter,编译报错(属性被@JvmSynthetic隐藏) // myObj.setOffset(2); // 无法访问
回答你的原始问题
- 隐藏Kotlin属性不让Java访问:有,就是
@JvmSynthetic注解,它能让Java完全看不到Kotlin的属性及自动生成的getter/setter - 隐藏Java方法(或给Java用的Kotlin方法)不让Kotlin访问:可以用
@Deprecated(message = "...", level = DeprecationLevel.HIDDEN),Kotlin会完全隐藏该方法,而Java不受影响
内容的提问来源于stack exchange,提问作者tekgator
相关产品推荐
相关产品推荐

