持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第23天,点击查看活动详情
本篇文章介绍两个kotlin中经常使用到的小技巧:
抽象属性
的两个实现姿势、kotlin接口默认实现的方法java不能直接用
。
历史文章
抽象属性
的两个实现姿势
现在有这样的代码,父类ParentJK
,子类BigJK
、SmallJK
:
abstract class ParentJK {
abstract val content: String
}
class SmallJK: ParentJK() {
override val content: String
get() = " i am small jk"
}
class BigJK: ParentJK() {
override val content: String = " i am small jk"
}
子类对于抽象属性content
实现方式不同,一个直接赋值,一个重写了get访问器,这两个有什么区别呢,我们看下反编译后的java代码:
ParentJK
父类:
public abstract class ParentJK {
@NotNull
public abstract String getContent();
}
就是提供了一个getContent()
抽象方法供子类重写。
SmallJK
方式:
public final class SmallJK extends ParentJK {
@NotNull
public String getContent() {
return " i am small jk";
}
}
这种方式只是重写了方法getContent()
,并没有额外定义其他的属性,没有带来其他开销。
BigJK
方式:
public final class BigJK extends ParentJK {
@NotNull
private final String content = " i am small jk";
@NotNull
public String getContent() {
return this.content;
}
}
这个方式除了重写了方法getContent()
,还额外定义了一个属性content
。
经过上面对比我们可以发现,BigJK
重写的父类的抽象属性content
,和SmallJK
比较起来,会额外定义一个content
字段带来开销。
所以,我们要根据不同的业务场景选择不同的重写方式:
当重写的属性返回的对象只需要初始化一次,下次获取相同对象时,我们可以选择
BigJK
方式,其他情况下就可以考虑SmallJK
方式,
kotlin接口默认实现的方法为啥java不能使用?
大家都知道,使用kotlin
定义接口时,可以给接口方法默认实现,这样子类就可以选择性重写接口方法了:
interface JKWonderful {
fun look() {
println("JKWonderful: look")
}
}
这样子类就不用额外重写look()
方法了:
上面这样写不会报错,我们看下在java中是不是也可以这样写:
可以看到直接报错了,编译器提醒我们要重写look()
方法。想要知道原因,我们就得把JKWonderful
接口反编译的java代码拿来仔细瞧瞧:
public interface JKWonderful {
void look();
public static final class DefaultImpls {
public static void look(@NotNull JKWonderful $this) {
String var1 = "JKWonderful: look";
System.out.println(var1);
}
}
}
可以看到并不是JKWonderful
接口真正的重写了look()
(这在java中也不可能,除非加个default关键字),所以实现这个接口却不是重写方法在java中肯定报错。
那为啥kotlin不重写接口方法不会报错呢,继续看下JKThinLeg
这个子类:
public final class JKThinLeg implements JKWonderful {
public void look() {
JKWonderful.DefaultImpls.look(this);
}
}
kotlin编译器已经帮我们处理好了,在JKWonderful
的子类JKThinLeg
中自动帮助我们重写了方法look()
,并默认调用了DefaultImpls.look()
的代码逻辑。
如果调用给这个接口方法look()
添加一个@JvmSynthetic
注解,在java中就不会报错了,也不会提醒实现这个方法,因为这个注解对于实现了这个接口的java类,相当于抹除了这个方法,自然就正常了。