一篇文章弄懂kotlin的扩展方法
Usage
扩展函数是kotlin的又一杀手锏功能,能够在不修改源码的基础上,扩展某些类的能力,方便开发。
例如这里演示了给String添加一个获取第一个元素的方法。
funString.first():Char{
if(isEmpty()){
throwNoSuchElementException("Stringisempty")
}
returnthis[0]
}
funmain(args:Array){
println("Hello,World".first())
}
这里需要额外注意的地方在于扩展函数的方法体中,是能够直接访问扩展对象public的变量的。例如上面的方法里面,我们也可以这么写:
funString.first():Char{
if(length<1){
throwNoSuchElementException("Stringisempty")
}
returnthis[0]
}
通过this可以在方法内,访问扩展对象,这里就是通过this[0]拿到第一个字符的。
Underinhood
看上去很厉害哈,但他的原理却非常简单。我们要时刻记住,kotlinJVM是基于JVM开发的,kotlin源码最后会变成字节码而后被运行。当遇到语法上不太懂的地方,直接反编译字节码,或者Decompile成Java方法,就能洞察里面的玄机。
我们将上述代码,Decompile成Java后,就能发现里面的秘密。
publicstaticfinalcharfirst(@NotNullString$this$first){
Intrinsics.checkParameterIsNotNull($this$first,"$this$first");
if($this$first.length()<1){
throw(Throwable)(newNoSuchElementException("Stringisempty"));
}else{
return$this$first.charAt(0);
}
}
原来是生成了一个publicstaticfinal的方法呀,不过这个生成是kotlin提供的语法糖,帮我们完成的。看到这个代码,也解释了为什么在扩展对象方法内部,能够访问到扩展对象的public成员。
重载与多态
扩展方法能否被继承呢,或者重载呢?我们来看看例子
openclassAnimal classDog:Animal() funAnimal.desc()="Animal" funDog.desc()="Dog" funmain(args:Array){ println(Dog().desc()) varanimal:Animal=Dog() println(animal.desc()) } //output: //Dog //Animal
如果扩展方法能够被重载,那么两次都应该输出Dog,我们还是和前面方法一样,来看看真相。
@NotNull
publicstaticfinalStringdesc(@NotNullAnimal$this$desc){
Intrinsics.checkParameterIsNotNull($this$desc,"$this$desc");
return"Animal";
}
@NotNull
publicstaticfinalStringdesc(@NotNullDog$this$desc){
Intrinsics.checkParameterIsNotNull($this$desc,"$this$desc");
return"Dog";
}
可以看到实际生成了两个desc方法,里面的参数不动,所以这个方法的调用,只与扩展对象本身有关系,在编译时已经确定,不存在多态。
扩展属性
这是一个很神奇的设定,kotlin并不能真的给扩展对象添加一个属性,而只是提供了一个语法糖,什么意思呢?我们具体看看下面这个例子。
varString.first:Char
get(){
if(isEmpty()){
throwNoSuchElementException(“Stringisempty”)
}
returnthis[0]
}
set(value){
println(“setvalueto$value”)
}
funmain(){
“Hello,World”.first=‘G'
println(“Hello,World”.first)
}
我们扩展了kotlin的属性,添加了一个first。我们可以分别给这个所谓的first属性,注意是所谓的,添加get和set方法。然后我们可以通过=和.来调用set和get方法,就像main方法中那样。但实际上,最后并没有生成first属性,我们来看看反编译过后的代码。
publicstaticfinalChargetFirst(@NotNullString$this$first){
Intrinsics.checkParameterIsNotNull($this$first,"$this$first");
CharSequencevar1=(CharSequence)$this$first;
booleanvar2=false;
if(var1.length()==0){
throw(Throwable)(newNoSuchElementException("Stringisempty"));
}else{
return$this$first.charAt(0);
}
}
publicstaticfinalvoidsetFirst(@NotNullString$this$first,charvalue){
Intrinsics.checkParameterIsNotNull($this$first,"$this$first");
Stringvar2="setvalueto"+value;
booleanvar3=false;
System.out.println(var2);
}
看到没有,实际上只是添加了setFirst和getFirst两个方法,并没有实际的属性添加上去。这也是kotlin提供给我们的语法糖之一,糖要吃,但也要小心蛀牙哦!
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对毛票票的支持。