一篇文章弄懂kotlin的扩展方法

一篇文章弄懂kotlin的扩展方法,第1张

概述一篇文章弄懂kotlin的扩展方法 Usage 扩展函数是 kotlin 的又一杀手锏功能,能够在不修改源码的基础上,扩展某些类的能力,方便开发. 例如这里演示了给 String 添加一个获取第一个元素的方法. fun String.first(): Char { if (isEmpty()) { throw NoSuchElementException("String is empty") } return this[0] } fun main(args: Array<String>) { pri ...

Usage

扩展函数是 kotlin 的又一杀手锏功能,能够在不修改源码的基础上,扩展某些类的能力,方便开发。

例如这里演示了给 String 添加一个获取第一个元素的方法。

fun String.first(): Char {  if (isEmpty()) {    throw NoSuchElementException("String is empty")  }  return this[0]}fun main(args: Array<String>) {  println("Hello,World".first())}

这里需要额外注意的地方在于扩展函数的方法体中,是能够直接访问扩展对象 public 的变量的。例如上面的方法里面,我们也可以这么写:

fun String.first(): Char {  if (length < 1) {    throw NoSuchElementException("String is empty")  }  return this[0]}

通过 this 可以在方法内,访问扩展对象,这里就是通过 this[0] 拿到第一个字符的。

Under in hood

看上去很厉害哈,但他的原理却非常简单。我们要时刻记住,kotlin JVM 是基于 JVM 开发的,kotlin 源码最后会变成字节码而后被运行。当遇到语法上不太懂的地方,直接反编译字节码,或者 Decompile 成 Java 方法,就能洞察里面的玄机。

我们将上述代码,Decompile 成 Java 后,就能发现里面的秘密。

public static final char first(@NotNull String $this$first){  Intrinsics.checkParameterIsNotNull($this$first,"$this$first");  if ($this$first.length() < 1) {   throw (Throwable)(new NoSuchElementException("String is empty"));  } else {   return $this$first.charat(0);  }}

原来是生成了一个 public static final 的方法呀,不过这个生成是 kotlin 提供的语法糖,帮我们完成的。看到这个代码,也解释了为什么在扩展对象方法内部,能够访问到扩展对象的 public 成员。

重载与多态

扩展方法能否被继承呢,或者重载呢?我们来看看例子

open class Animalclass Dog : Animal()fun Animal.desc() = "Animal"fun Dog.desc() = "Dog"fun main(args: Array<String>) {  println(Dog().desc())  var animal: Animal = Dog()  println(animal.desc())}// output:// Dog// Animal

如果扩展方法能够被重载,那么两次都应该输出 Dog,我们还是和前面方法一样,来看看真相。

@NotNullpublic static final String desc(@NotNull Animal $this$desc) {  Intrinsics.checkParameterIsNotNull($this$desc,"$this$desc");  return "Animal";}@NotNullpublic static final String desc(@NotNull Dog $this$desc) {  Intrinsics.checkParameterIsNotNull($this$desc,"$this$desc");  return "Dog";}

可以看到实际生成了两个 desc 方法,里面的参数不动,所以这个方法的调用,只与扩展对象本身有关系,在编译时已经确定,不存在多态。

扩展属性

这是一个很神奇的设定,kotlin 并不能真的给扩展对象添加一个属性,而只是提供了一个语法糖,什么意思呢?我们具体看看下面这个例子。

var String.first: Char  get() {    if (isEmpty()) {      throw NoSuchElementException(“String is empty”)    }    return this[0]  }  set(value) {    println(“set value to $value”)  }fun main() {  “Hello,World”.first = ‘G'  println(“Hello,World”.first)}

我们扩展了 kotlin 的属性,添加了一个 first。我们可以分别给这个所谓的 first 属性,注意是所谓的,添加 get 和 set 方法。然后我们可以通过 = 和 . 来调用 set 和 get 方法,就像 main 方法中那样。但实际上,最后并没有生成 first 属性,我们来看看反编译过后的代码。

public static final Char getFirst(@NotNull String $this$first) {  Intrinsics.checkParameterIsNotNull($this$first,"$this$first");  CharSequence var1 = (CharSequence)$this$first;  boolean var2 = false;  if (var1.length() == 0) {   throw (Throwable)(new NoSuchElementException("String is empty"));  } else {   return $this$first.charat(0);  }}public static final voID setFirst(@NotNull String $this$first,char value) {  Intrinsics.checkParameterIsNotNull($this$first,"$this$first");  String var2 = "set value to " + value;  boolean var3 = false;  System.out.println(var2);}

看到没有,实际上只是添加了 setFirst 和 getFirst 两个方法,并没有实际的属性添加上去。这也是 kotlin 提供给我们的语法糖之一,糖要吃,但也要小心蛀牙哦!

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。

总结

以上是内存溢出为你收集整理的一篇文章弄懂kotlin的扩展方法全部内容,希望文章能够帮你解决一篇文章弄懂kotlin的扩展方法所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1145750.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存