Kotlin里的Extension Functions实现原理分析

简介: ## Kotlin里的Extension Functions Kotlin里有所谓的扩展函数(Extension Functions),支持给现有的java类增加函数。 * https://kotlinlang.org/docs/reference/extensions.html 比如给`String`增加一个`hello`函数,可以这样子写: ```java

Kotlin里的Extension Functions

Kotlin里有所谓的扩展函数(Extension Functions),支持给现有的java类增加函数。

比如给String增加一个hello函数,可以这样子写:

fun String.hello(world : String) : String {
    return "hello " + world + this.length;
}
fun main(args: Array<String>) {
    System.out.println("abc".hello("world"));
}

可以看到在main函数里,直接可以在String上调用hello函数。

执行后,输出结果是:

hello world3

可以看到在hello函数里的this引用的是"abc"。

刚开始看到这个语法还是比较新奇的,那么怎样实现的呢?如果不同的库都增加了同样的函数会不会冲突?

反编绎生成的字节码,结果是:

  @NotNull
  public static final String hello(@NotNull String $receiver, @NotNull String world) {
    return "hello " + world + $receiver.length();
  }
  public static final void main(@NotNull String[] args) {
    System.out.println(hello("abc", "world"));
  }

可以看到,实际上是增加了一个static public final函数。

并且新增加的函数是在自己的类里的,并不是在String类里。即不同的库新增加的扩展函数都是自己类里的,不会冲突。

lombok 里的 @ExtensionMethod 实现

lombok里也提供了类似的@ExtensionMethod支持。

和上面的例子一样,给String类增加一个hello函数:

  • 需要定义一个class Extensions
  • 再用@ExtensionMethod声明
class Extensions {
    public static String hello(String receiver, String world) {
        return "hello " + world + receiver.length();
    }
}
@ExtensionMethod({
        Extensions.class
})

public class Test {
    public static void main(String[] args) {
        System.out.println("abc".hello("world"));
    }
}

执行后,输出结果是:

hello world3

可以看到在hello函数里,第一个参数String receiver就是"abc"本身。

和上面kotlin的例子不一样的是,kotlin里直接可以用this。

生成的字节码反编绎结果是:

class Extensions {
  public static String hello(String receiver, String world) {
    return "hello " + world + receiver.length();
  }
}
public class Test {
  public static void main(String[] args) {
    System.out.println(Extensions.hello("abc", "world"));
  }
}

可以看到所谓的@ExtensionMethod实际上也是一个语法糖。

设计动机

据kotlin的文档:各种FileUtils,StringUtils类很麻烦。

比如像下面处理List,在java里可以用java.util.Collections

// Java
Collections.swap(list, Collections.binarySearch(list,
    Collections.max(otherList)),
    Collections.max(list));

简化下import,可以变为

// Java
swap(list, binarySearch(list, max(otherList)), max(list));

但是还不够清晰,各种import *也是比较烦的。利用扩展函数,可以直接这样子写:

// Java
list.swap(list.binarySearch(otherList.max()), list.max());

总结

  • kotlin的Extension Functions和lombok的@ExtensionMethod实际上都是增加public static final函数
  • 不同的库增加的同样的Extension Functions不会冲突
  • 设计的动机是减少各种utils类。
相关文章
|
Kotlin
Kotlin | 实现数据类(data)深拷贝
在Kotlin中,data数据类默认的copy方法实现的是浅拷贝,但我们有时候需要实现深拷贝。 在kotlin中,实现就比较容易了。
1257 0
Kotlin | 实现数据类(data)深拷贝
|
设计模式 Kotlin
Kotlin设计模式实现之装饰者模式(Decorator)
装饰者模式(Decorator):在不改变对象自身的基础上,动态地给一个对象添加一些额外的职责。与继承相比,装饰者是一种更轻便灵活的做法。若要扩展功能,装饰者提供了比继承更有弹性的替代方法。
406 1
Kotlin设计模式实现之装饰者模式(Decorator)
|
设计模式 算法 Kotlin
Kotlin设计模式实现之策略模式
Kotlin设计模式实现之策略模式
400 0
Kotlin设计模式实现之策略模式
|
存储 Kotlin
数据结构 | 二分搜索树及它的各种操作(kotlin实现)
在开始之前,应该先讲一下什么是二叉树。
342 0
数据结构 | 二分搜索树及它的各种操作(kotlin实现)
|
存储 C语言 Kotlin
重学数据结构-使用Kotlin实现链表及其他扩展
很简单,链表不像数组那样,不需要我们主动扩容,我们只需要类似递归一样,一层套一层即可,即node1持有node2的引用,node2持有node3…,相应的每次插入我们只需要更改头结点即可,当node-x持有的下一个node引用为null时,我们也可以判定,此时为链表尾节点。
486 0
|
算法 Kotlin
数据结构 | 使用Kotlin实现栈与队列
Last In First Out(LIFO) 后进先出 栈也是一种线性数据结构
1194 0
|
存储 Kotlin
用kotlin来实现一个打方块的小游戏
用kotlin来实现一个打方块的小游戏
338 0
用kotlin来实现一个打方块的小游戏
|
Kotlin
用kotlin来实现一个饼图
用kotlin来实现一个饼图
344 0
用kotlin来实现一个饼图
|
网络协议 Java Android开发
基于Kotlin实现一个简单的TCP自定义协议
一. 开发背景 想要成为一名优秀的Android开发,你需要一份完备的 知识体系,在这里,让我们一起成长为自己所想的那样~。
基于Kotlin实现一个简单的TCP自定义协议
|
JSON Java 数据格式
基于 Kotlin + OkHttp 实现易用且功能强大的网络框架(一)
基于 Kotlin + OkHttp 实现易用且功能强大的网络框架(一)
1222 0
基于 Kotlin + OkHttp 实现易用且功能强大的网络框架(一)