Kotlin-拓展功能
来源:互联网 发布:金融软件供应商 编辑:程序博客网 时间:2024/06/05 07:39
Kotlin跟C#和Gosu一样简洁,提供了在不必继承类或使用任何类型的设计模式(如装饰器)的情况下扩展新功能的类的能力。 这是通过称为扩展的特殊声明完成的。Kotlin支持扩展函数和扩展属性
扩展函数
声明拓展函数,我们需要在接收器类型名称的后面像后缀一样添加,以下就是一个例子,在MutableList后面添加一个swap拓展函数:
fun MutableList<Int>.swap(index1 :Int,index2 :Int){ val tmp=this[index1]; this[index1]=this[index2]; this[index2]=tmp;}
在这个拓展函数中的this代表的是这个接收对象(就是点号前面的对象).从上面那样定义拓展函数后,我们就可以使用了:
val list=mutableListOf(1,2,3)list.swap(0,2);
当然这个函数我们可以设计得更通用些,比如下面这样:
fun <T> MutableList<T>.swap(index1:Int,index2:Int){ val tmp=this[index1]; this[index1]=this[index2]; this[index2]=tmp}
我们在函数名前面定义了一个泛型参数,方便在接收器中确定类型。
静态的拓展解决方案
事实上,拓展函数在定义之后就不方便更改了.定义拓展函数后,就不可以插入新成员到类中了,但是可以通过这种方式来调用新函数。
在这里,我们强调的是,拓展函数是静态的。也就是说,对于接收器类型来说,拓展函数不是虚拟的。这就说明,拓展函数会被调用是由表达式来确定,而不是由表达式计算结果的类型来确定。
open class Cclass D:C()fun C.foo()="c"fun D.foo()="d"fun printFoo(c:C){ println(c.foo());}printFoo(D());
这个例子中将会打印’c’,因为拓展函数(printFoor)的调用依赖于它的参数(c:C)
如果一个类中,有成员函数和拓展函数同名,那么成员函数的优先级总是比较高,总会是优先。
class E{ fun foor(){ println("member"); }}fun C.foor(){ println("extension");}
当E类的所有实例调用 foor的时候,总会调用到成员函数。然而,相同名字也可以区分,比如可以用不同参数来区别,
class F{ fun foo(){ println("I am member"); }}fun foo(i:Int){ println("I am extension $i");}
进行调用的时候,F().foo()是成员函数,而F().foo(12)则是拓展函数
可为空的接收器
这里有一个需要注意的地方就是,拓展函数可以定义在空的接收器类型上。对象的实例在为空的情况下还是可以调用拓展函数,但在函数中需要检查实例是否非空,进行不同的处理,从这里可以知道,在Kotlin中,你可以不用检查非空就可以使用toString(),非空检查可以放在内部的拓展函数里面。
fun Any?.toString():String{ if(this ==null)return "null" return toString()}
拓展属性
和拓展函数一样,Kotlin也支持拓展属性:
val <T> List<T>.lastIndex:Int get()=size - 1
需要注意的是,添加拓展属性之后就不要再插入成员(变量和成员属性)了,拓展属性没有支持隐性字段的方法,这就是为什么不允许初始化拓展属性.他们更改的动作只能通过明确的getter和setter来操作。
val Foo.bar=1 //这是错误的方式,不允许这样初始化拓展属性
拓展衍生对象(Companion Object Extensions)
如果一个类定义了衍生对象,你也可以定义对应的拓展函数和拓展属性
class MK{ companion object{}}fun MK.Companion.food(){ //...}
这个衍生对象的调用和成员方法的调用有点小区别,他们只能通过类名来直接调用
MK.food()
拓展的范围
多数情况下,我们定义拓展都是直接定义在顶级,比如定义在包下:
package com.mkfun MK.operation(){...}
在其他包内使用这些拓展,我们需要导入
package com.mk.utilimport com.mk.MK.operationfun usage(mk:MK){ mk.operation()}
把拓展当做成员来声明
在类的内部,你可以把拓展声明成另外一个类,在拓展内部,有多个隐式接收器,可以不需要修饰符就可以访问对象成员.声明拓展的类的实例称为分派接收器.拓展方法的接收器实例则称为拓展接收器
class D { fun bar() { ... }}class C { fun baz() { ... } fun D.foo() { bar() // calls D.bar baz() // calls C.baz } fun caller(d: D) { d.foo() // call the extension function }}
当遇上分派接收器和拓展接收器的成员名冲突时,拓展接收器的成员优先级比较高,要引用分派接收器的成员,你可以使用限定的语法
class C { fun D.foo() { toString() // 调用 D.toString() this@C.toString() // 调用 C.toString() }
被声明成成员的拓展如果可以被子类重写也是需要用open来修饰,这意味着对于分派接收器类型而言,此类功能的调度是虚拟的,但对于扩展接收器类型来说是静态的
open class D {}class D1 : D() {}open class C { open fun D.foo() { println("D.foo in C") } open fun D1.foo() { println("D1.foo in C") } fun caller(d: D) { d.foo() // call the extension function }}class C1 : C() { override fun D.foo() { println("D.foo in C1") } override fun D1.foo() { println("D1.foo in C1") }}C().caller(D()) // prints "D.foo in C"C1().caller(D()) // prints "D.foo in C1" - dispatch receiver is resolved virtuallyC().caller(D1()) // prints "D.foo in C" - 拓展接收器是静态调用
设计拓展的缘由
在Java中,我们经常用”*Utils”来命名:FileUtils,StringUtils等,著名的java.util.Collections就是一个示例,对于这些工具类,我们这样用:
//JavaCollections.swap(list, Collections.binarySearch(list, Collections.max(otherList)), Collections.max(list))
那些类名让我们用起来很不爽,我可以用静态导入:
//Javaswap(list, binarySearch(list, max(otherList)), max(list))
到这里为止,已经好一点了,但我们还是没有在IDE强大的代码辅助功能中得到什么帮助,如果还有更好,那就是下面这样:
// Javalist.swap(list.binarySearch(otherList.max()), list.max())
但我们并不想全部都这样来实现,那么这时候,拓展就可以帮助我们了。
- Kotlin-拓展功能
- Kotlin Android 拓展包
- kotlin拓展属性和官方文档中的拓展
- Swing拓展JTree功能
- 拓展JTree的功能
- openlayers3功能拓展
- android按键功能的拓展
- 腾讯通RTX拓展功能
- Vim拓展功能及命令
- Sublime功能拓展及插件
- SharpMap功能拓展之空间分析功能
- TinyDuino使用W5200拓展以太网功能
- MyEclipse 10.7中拓展自动提示功能
- UAP拓展按钮自定义功能方法步骤
- 通用选择框的功能拓展
- 拓展编辑器功能--Unity自定义编辑器窗口
- Unity3D之Shader自定义编辑器功能拓展
- SnapHelper,对RecyclerView的功能拓展
- 团队协作及scrum sprint story编写
- lvs与nginx区别
- 画圆拖动0630
- How can I convert printStackTrace message to a string?
- 怎样将discuz所有页面的Powered by Discuz!去掉
- Kotlin-拓展功能
- 光照(light)
- Spring属性注入的两种方式
- 优化mysql数据库的几个步骤
- 二分图最大匹配总结
- 数据库 学习一
- 如何获取事件冒泡里最顶层的元素(或者任意层的元素)
- 我如何找到了Facebook广告服务的信息泄漏漏洞(奖金高达10000美刀)
- ecnu 电话送报 贪心