Kotlin扩展函数及实现机制的深入探索扩展函数及实现机制的深入探索
扩展函数与扩展属性的神奇之处在于,可以在不修改原来类的条件下,使用函数和属性,表现得就像是属于这个类的一样。下面这篇文章主要给大家介绍了关于Kotlin扩展函数及实
现机制的相关资料,需要的朋友可以参考下
前言前言
2017年Google IO大会宣布使用Kotlin作为Android的官方开发语言,相比较与典型的面相对象的JAVA语言,Kotlin作为一种新式的函数式编程语言,也有人称之为Android平台的Swift语言。
先让我们看下实现同样的功能,Java和Kotiln的对比:
// JAVA,20多行代码,充斥着findViewById,类型转换,匿名内部类这样的无意义代码
public class MainJavaActivity extends Activity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView label = (TextView) findViewById(R.id.label);
Button btn = (Button) findViewById(R.id.btn);
label.setText("hello");
label.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Glen","onClick TextView");
}
});
btn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Log.d("Glen","onClick Button");
}
});
}
}
再来看Kotlin
// Kotlin,没有了冗余的findViewById,我们可以直接对资源id进行操作,也不需要匿名内部类的声明,更关注函数的实现本身,抛弃了复杂的格式
class MainKotlinActivity:Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
R.id.label.setText("hello")
R.id.label.onClick { Log.d("Glen","onClick TextView") }
R.id.btn.onClick { Log.d("Glen","onClick Button") }
}
}
实现这些需要借助Kotlin的扩展函数与高阶函数,本文主要介绍一下扩展函数。
什么是扩展函数?什么是扩展函数?
扩展函数数是指在一个类上增加一种新的行为,甚至我们没有这个类代码的访问权限。这是一个在缺少有用函数的类上扩展的方法,Kotlin能够为我们做到那些令人关注的事情,而这些Java做不到。
在Java中,通常会实现很多带有static方法的工具类,而Kotlin中扩展函数的一个优势是我们不需要在调用方法的时候把整个对象当作参数传入,它表现得就像是属于这个类的一样,而且我们可以使用this
关键字和调用所有public方法。
1. Kotlin 扩展函数与扩展属性扩展函数与扩展属性(Kotlin Extensions)
Kotlin 能够扩展一个类的新功能而无需继承该类,或者对任意的类使用像“装饰者(Decorator)”这样的设计模式。这些都是通过叫做“扩展(extensions)”的特殊声明实现的。Kotlin扩展声明既支持扩展函数也
支持扩展属性,本文主要讨论扩展函数,至于扩展属性实现的机制类似。
扩展函数的声明非常简单,他的关键字是.,此外我们需要一个“接受者类型(recievier type)”来作为他的前缀。以类MutableList<Int>为例,现在为它扩展一个swap方法,如下:
fun MutableList<Int>.swap(index1:Int,index2:Int) {
val tmp = this[index1]
this[index1] = this[index2]
this[index2] = tmp
}
MutableList<T>是kotlin提供的基础库collection中的List容器类,这里在声明里作为“接受者类型”,.作为声明关键字,swap是扩展函数名,其余和Kotlin声明一个普通函数并无区别。
额外提一句,Kotlin的this语法要比JAVA更灵活,这里扩展函数体里的this代表的是接受者类型对象。
如果我们想要调用这个扩展函数,可以这样:
fun use(){
val list = mutableListOf(1,2,3)
list.swap(1,2)
}
2. Kotlin扩展函数是怎么实现的扩展函数是怎么实现的
扩展函数的调用看起来就像是原生方法一样自然,使用起来也非常顺手,但是这样的方法会不会带来性能方面的掣肘呢?有必要探究一下Kotlin是如何实现扩展函数的,直接分析Kotlin源码难度还是挺
大,还好Android Studio提供了一些工具,我们可以通过Kotlin ByteCode指令,查看Kotlin语言转换的字节码文件,仍以MutableList<Int>,swap为例,转换为字节码之后的文件如下:
// ================com/example/glensun/demo/extension/MutableListDemoKt.class =================
// class version 50.0 (50)
// access flags 0x31
public final class com/example/glensun/demo/extension/MutableListDemoKt {
// access flags 0x19
// signature (Ljava/util/List<Ljava/lang/Integer;>;II)V
// declaration: void swap(java.util.List<java.lang.Integer>, int, int)
public final static swap(Ljava/util/List;II)V
@Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
L0
ALOAD 0
LDC "$receiver"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
L1
LINENUMBER 8 L1
ALOAD 0
ILOAD 1
INVOKEINTERFACE java/util/List.get (I)Ljava/lang/Object;
CHECKCAST java/lang/Number
INVOKEVIRTUAL java/lang/Number.intValue ()I
ISTORE 3
L2
LINENUMBER 9 L2
ALOAD 0
ILOAD 1
ALOAD 0
ILOAD 2
INVOKEINTERFACE java/util/List.get (I)Ljava/lang/Object;
INVOKEINTERFACE java/util/List.set (ILjava/lang/Object;)Ljava/lang/Object;
POP
L3