如何在Java 11中使用带默认值属性的Kotlin 1.6.21接口
Kotlin 1.6.21带默认属性的接口在Java 11中的使用问题及解决
我用Kotlin 1.6.21定义了一个带有默认属性和默认方法的接口,在Kotlin中可以正常实现,但在Java 11中使用时遇到了编译问题,具体情况如下:
Kotlin接口定义
interface ISomeKInterface { val flag: Int get() = 1 fun onProc(data: String) { if (flag == 1) { // 执行操作1 } else if (flag == 2) { // 执行操作2 } else { // 执行其他操作 } } }
Kotlin中的实现示例
在Kotlin中可以直接实现该接口,支持重写属性值或属性的getter方法:
// 直接重写属性值的实现 object : ISomeKInterface { override val flag: Int = 2 override fun onProc(data: String) { if (flag == 1) { // 执行操作1 } else if (flag == 2) { // 针对flag=2的自定义实现 } else { // 执行其他操作 } } }
补充说明:
Kotlin中还可以通过重写属性的getter方法来实现自定义逻辑,效果和直接重写属性值一致:
fun test_() { val theInterfaceImpl: ISomeKInterface = object : ISomeKInterface { // 方式1:直接重写属性值 // override val flag: Int = 2 // 方式2:重写getter方法,可访问父类默认值 override val flag: Int get() { val superFlag: Int = super.flag println("+++ 测试重写getter方法,父类flag值:$superFlag,返回flag值:2") return 2 } // 不需要修改默认实现时,可省略onProc的重写 override fun onProc(data: String) { println("+++ 测试重写onProc方法,当前flag值:$flag,调用默认onProc处理数据:$data") super.onProc(data) } } val flag = theInterfaceImpl.flag println("+++ 当前flag值:$flag") theInterfaceImpl.onProc("eee888") }
Java中遇到的问题
在Java 11中使用该接口时,会出现以下编译问题:
- Java强制要求重写
onProc(String)方法,即使接口已有默认实现 - 无法直接调用接口的默认
onProc实现 - 无法直接获取父类
flag的默认值
Java测试代码及报错
@Test public void test_() { ISomeKInterface theInterfaceImpl = new ISomeKInterface() { @Override public int getFlag() { // int superFlag = ISomeKInterface.super.getFlag(); // <== 此处报错,无法访问父类默认值 // System.out.println("+++ 父类flag值:"+superFlag+",返回flag值:"+2); return 2; } @Override public void onProc(@NonNull String data) { // Java要求必须实现该方法,无法直接使用默认实现 System.out.println("+++ 测试重写onProc方法,处理数据:"+data); ISomeKInterface.super.onProc(data); // <=== 此处编译报错 } }; int flag = theInterfaceImpl.getFlag(); System.out.println("+++ 当前flag值:"+flag); theInterfaceImpl.onProc("eee888"); }
报错信息:
error: abstract method onProc(String) in ISomeKInterface cannot be accessed directly ISomeKInterface.super.onProc(data); //<=== ^
解决方法
1. 配置Kotlin接口兼容Java默认方法
Kotlin接口的默认方法默认不会编译为Java 8+的默认方法,需要添加@JvmDefault注解并启用编译配置:
修改Kotlin接口
interface ISomeKInterface { val flag: Int get() = 1 @JvmDefault fun onProc(data: String) { if (flag == 1) { // 执行操作1 } else if (flag == 2) { // 执行操作2 } else { // 执行其他操作 } } }
启用JVM默认方法编译配置
在项目的Gradle配置中添加编译参数:
- Gradle Kotlin DSL (
build.gradle.kts):
tasks.withType<KotlinCompile> { kotlinOptions { freeCompilerArgs = listOf("-Xjvm-default=all") } }
- Gradle Groovy DSL (
build.gradle):
tasks.withType(KotlinCompile) { kotlinOptions { freeCompilerArgs = ['-Xjvm-default=all'] } }
说明:
-Xjvm-default=all会将所有Kotlin接口默认方法编译为Java默认方法;若只想对添加@JvmDefault的方法生效,可改用-Xjvm-default=enable。
2. Java中正确调用默认方法和获取父类属性值
配置完成后,Java代码可以通过DefaultImpls静态类访问接口的默认实现:
@Test public void test_() { ISomeKInterface theInterfaceImpl = new ISomeKInterface() { @Override public int getFlag() { // 通过DefaultImpls获取父类flag的默认值 int superFlag = ISomeKInterface.DefaultImpls.getFlag(this); System.out.println("+++ 父类flag值:"+superFlag+",返回flag值:"+2); return 2; } @Override public void onProc(@NonNull String data) { System.out.println("+++ 测试重写onProc方法,处理数据:"+data); // 通过DefaultImpls调用接口的默认onProc实现 ISomeKInterface.DefaultImpls.onProc(this, data); } }; int flag = theInterfaceImpl.getFlag(); System.out.println("+++ 当前flag值:"+flag); theInterfaceImpl.onProc("eee888"); }
3. 避免重写默认方法的方案
如果不想重写onProc方法,可以在Kotlin中创建一个抽象适配器类,然后Java继承该类:
// Kotlin中定义抽象适配器类 abstract class SomeKInterfaceAdapter : ISomeKInterface
Java中使用:
ISomeKInterface theInterfaceImpl = new SomeKInterfaceAdapter() { @Override public int getFlag() { return 2; } }; // 直接使用接口的默认onProc方法 theInterfaceImpl.onProc("test data");
内容的提问来源于stack exchange,提问作者lannyf
相关产品推荐
相关产品推荐

