Java与Kotlin混合编程之@JvmDefault

在这里插入图片描述
虽然kotlin与Java很好地进行了兼容,但使用不当仍然会遇到不少问题。

1. 问题:无法代理default方法


我们定一个包含default方法的Java接口及其实现类

//Base.java
public interface Base {
    default void print() {
        System.out.println("Base");
    }
}

//BaseImpl.java
class BaseImpl implements Base {
    @Override
    public void print() {
        System.out.println("BaseImpl");
    }
}

此接口如果用做koltlin的类代理中:

//Derived.kt

class Derived(b: Base) : Base by b

fun main() {
    val b = BaseImpl()
    Derived(b).print()
}

输出结果:
在这里插入图片描述

虽然代理对象是BaseImpl,但其print()方法并没有被重写,依然是执行的default的方法。


2. 原因分析


by关键字本质上是一个语法糖,帮你省略代理模式所需的模板代码,但是java接口的default方法不会被代理
在这里插入图片描述
kt反编译后的java代码可以看到,并没有实现print()方法


3. Kotlin没有default方法


使用kotlin定义接口Base,其他保持不变

//Base.kt
interface Base {
    fun print() {
        print("Base")
    }
}

此时反编译
在这里插入图片描述
可以返现,print()方法被正常代理了

Kotlin接口虽然可以定义方法体实现,但是实现机制与java的default方法实现机制不同,Kotlin中也没有default关键字
在这里插入图片描述
Base通过DefaultImpls静态类添加默认实现,其子类可以通过super调用实现

Kotlin子类

Kotlin中定义BaseImpl

class BaseImpl : Base {
    override fun print() {
        super.print()
        print("BaseImpl")
    }
}

在这里插入图片描述

Java子类

Kotlin接口中定义的方法体并非真正给你的default方法,所以当Java子类继承Kotlin接口时,仍然要重写print(),否则会报错
在这里插入图片描述
Kotlin接口的方法可以添加@JvmDefault注解,实现java中default关键字的效果:

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-default/

在这里插入图片描述

其中,最后一句话也很明确的说明了无法对default方法进行代理


4. 结论


回到本文最初的问题,我们因该怎么避免呢?

首先,应该尽量避免Kotlin和Java的混编,特别是避免在继承上产生关系,让上帝的归上帝,凯撒的归凯撒
在这里插入图片描述

若迫不得已需要像本例一样(在Kotlin中实现一个Java接口),当有default方法时,需要重写default方法,并手动调用代理,不要寄希望于by关键字

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fundroid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值