一篇文章弄懂kotlin的扩展方法
作者:DROID 发布时间:2022-06-05 08:06:20
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 Animal
class 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,我们还是和前面方法一样,来看看真相。
@NotNull
public static final String desc(@NotNull Animal $this$desc) {
Intrinsics.checkParameterIsNotNull($this$desc, "$this$desc");
return "Animal";
}
@NotNull
public 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 提供给我们的语法糖之一,糖要吃,但也要小心蛀牙哦!
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。
来源:https://woaitqs.cc/2019/09/08/kotlin-extension-method/


猜你喜欢
- 创建Avalonia的MVVM项目,命名DragDemo ,然后将项目的Nuget包更新到预览版<ItemGroup>
- “反射”其实就是利用程序集的元数据信息。 反射可以有很多方法,编写程序时请先导入 System.Reflection 命名空间。1、假设你要
- 一、insert1.插入操作public class CRUDTests { @Autowired
- 使用工具:Android studio 3.0使用方法:一:在build.gradle(Module:app)中添加依赖implementa
- pom.xml与settings.xmlpom.xml与setting.xml,可以说是Maven中最重要的两个配置文件,决定了Maven的
- cron表达式每天整点执行一次的问题最近写了个发短信的定时任务,需求是每天上午10点发信息,然后我百度了一篇文章,复制了一个cron表达式:
- 本文实例讲述了java使用归并删除法删除二叉树中节点的方法。分享给大家供大家参考。具体分析如下:实现的思想很简单:first:找到要删除的节
- 前些天,有一个需求要用SpringBoot的多环境,当时没有系统学习springboot ,所以在网上找来找去的找到了一个解决方案,并写了一
- 一、Java内存区域方法区(公有):用户存储已被虚拟机加载的类信息,常量,静态常量,即时编译器编译后的代码等数据。异常状态 OutOfMem
- 利用apache ftp工具实现文件的上传下载和删除,具体如下1、下载相应的jar包 com
- 在 Android 中倒计时功能是比较常用的一个功能,比如短信验证码,付款倒计时等。实现方式有Handler、Thread 等,但是实现起来
- 一. 什么是蓝牙(Bluetooth)?1.1 BuleTooth是目前使用最广泛的无线通信协议1.2 主要针对短距
- public static String toUtf8String(String s) {
- 相信不少喜欢开发的朋友都已经知道微信小程序是个什么物种了,楼主也是从小程序内测期间就开始关注,并且也写过几个已经上线的微信小程序。但是基本上
- 先看效果图:你可以定义成你项目的logo图片,可以设置水波颜色、波长、波宽、字体大小、颜色、进度条的最大值,当前进度值,还可以设置波纹震动的
- 前面已经认识了不同的数据类型,你们有没有尝试过让不同的数据类型进行运算呢?int a = 1;double b = a;Console.Wr
- 本文实例讲述了Android开发之imageView图片按比例缩放的实现方法。分享给大家供大家参考,具体如下:android:scaleTy
- 需求背景闲话不扯,直奔主题。需要和web前端建立长链接,互相实时通讯,因此想到了websocket,后面随着需求的变更,需要用户订阅主题,实
- SpringBoot集成Freemarker主要特征:静态页面,无接 * 互数据实时性不高且体量小的网站可采用生成静态html的形式数据提前渲
- Android Studio Intent隐式启动,发短信,拨号,打电话,访问网页等实例代码功能创建5个按钮,隐式启动、发短信、拨号按钮、电