Kotlin学习笔记3-5 类和对象-扩展
2018-01-23 14:48
561 查看
扩展
Kotlin官网:Classes and Objects-ExtensionsKotlin支持在一个类使用“扩展”增加功能,无需继承或者使用装饰模式之类的设计模式。
支持扩展函数和扩展属性。
扩展函数
声明扩展函数的格式为:被扩展类型.扩展函数名下例为给MutableList类型增加swap函数
fun MutableList<Int>.swap(index1: Int, index2: Int) { val tmp = this[index1] // 'this' corresponds to the list this[index1] = this[index2] this[index2] = tmp }
扩展函数中的this关键字指被扩展类型对象。
使用扩展函数:
val l = mutableListOf(1, 2, 3) l.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'l'
扩展函数适用于任何MutableList类型,声明为泛型:
fun <T> MutableList<T>.swap(index1: Int, index2: Int) { val tmp = this[index1] // 'this' corresponds to the list this[index1] = this[index2] this[index2] = tmp }
泛型的说明参考3-8
扩展是静态解析
扩展函数并未改变原类,仅仅是给这个类型增加了.调用函数的能力。对扩展函数的调用是静态分配的,由函数声明的类型决定,而不是在运行时动态解析。
父类和子类有同样的扩展函数
举个例子:open class C class D: C() fun C.foo() = "c" fun D.foo() = "d" fun printFoo(c: C) { println(c.foo()) } printFoo(D())
上例中打印结果为c,这是因为printFoo声明的参数类型为C,决定了使用C类型的扩展函数。
扩展函数和类的成员函数相同
扩展函数名和类成员函数名相同时,使用类的成员函数class C { fun foo() { println("member") } } fun C.foo() { println("extension") }
c.foo()是打印结果为”member”,而不是”extension”.
扩展函数重载成员函数
当扩展函数和成员函数的函数签名不同时,两者互不干扰。class C { fun foo() { println("member") } } fun C.foo(i: Int) { println("extension") }
调用C().foo(1) ,打印结果”extension”
可空扩展接收者
可以为可空类型增加扩展,在对象为空时也可以调用,在扩展函数中用this==null判断是否为空。这是Kotlin允许调用空对象的toString的原理。
fun Any?.toString(): String { if (this == null) return "null" // after the null check, 'this' is autocast to a non-null type, so the toString() below // resolves to the member function of the Any class return toString() }
扩展属性
和扩展函数类似,也是被扩展类型.属性名.必须通过自定义访问器实现。
val <T> List<T>.lastIndex: Int get() = size - 1
由于扩展并不是给原类型增加成员,所以不支持属性的后备字段,不支持初始化器。
扩展属性的行为是通过自定义访问器实现的。
伴生对象扩展
如果类有伴生对象,可以给伴生对象扩展属性和函数class MyClass { companion object { } // will be called "Companion" } fun MyClass.Companion.foo() { // ... }
伴生对象的扩展成员的调用方法和普通成员相同,类名.扩展成员名
扩展的作用域
大多数情况下扩展定义在顶层,例如包中package foo.bar fun Baz.goo() { ... }
在定义的包外使用需要导入
package com.example.usage import foo.bar.goo // 导入方法1:导入名为“goo”的扩展成员 import foo.bar.* // 导入方法2:导入foo.bar中的所有内容 fun usage(baz: Baz) { baz.goo() }
声明扩展为自己的成员
在类内部声明的其他类扩展,可以直接调用类中的成员,无需.声明。声明扩展的类的实例叫做分发接收者
被扩展类的实例叫做扩展接收者
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 } }
重名时被扩展的类的成员优先被调用,可以使用this关键字调用分发接受者的成员。
class C { fun D.foo() { toString() // calls D.toString() this@C.toString() // calls 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 virtually C().caller(D1()) // prints "D.foo in C" - extension receiver is resolved statically
上例中,对于C和C1是动态分配的,C1中D
a658
.foo被重写,caller打印出的是C1重写的D.foo。而对于caller函数中的d参数,由于是静态分配的,无论传入D的实例还是D1的实例,都会调用函数签名中D类的扩展函数D.foo,而不会去调用D1.foo。
为什么要使用扩展
为某些类添加工具方法。例如Java中的各种工具类,以java.utilCollections为例,使用时需要用Collections.方法名(集合实例,参数)这样调用。
Collections.swap(list, Collections.binarySearch(list, Collections.max(otherList)), Collections.max(list)); // import static swap(list, binarySearch(list, max(otherList)), max(list));
直接写成实例的方法最好
list.swap(list.binarySearch(otherList.max()), list.max());
但是又不想在List中添加所有可能使用的方法,这时可以使用扩展。xu
相关文章推荐
- [iphone 开发学习笔记]Object-C和C语言最大的区别也是最大的扩展-----消息(即如何调用一个对象中的函数)
- ECMAScript6学习笔记-对象扩展
- [原]Java程序员的JavaScript学习笔记(11——jQuery-在“对象”层面扩展)
- Kotlin学习笔记3-3 类和对象-接口
- ECMAScript 6 学习笔记----对象的扩展
- Kotlin学习笔记3-11 类和对象-对象
- 新手上路,Kotlin学习笔记(三)---类、对象、接口
- Java程序员的JavaScript学习笔记(11——jQuery-在“对象”层面扩展)
- C#特性 学习笔记(对象初始化器 匿名类型 扩展方法)
- Kotlin 学习笔记(八)—— Kotlin类与对象之接口
- Kotlin学习(四)—— 类和对象,继承,覆盖,抽象类,属性和字段,接口,可见性修饰符,扩展
- [Kotlin]Kotlin学习笔记(四):类与对象、泛型详解
- asp.net ajax 学习笔记--对javascript对象的扩展
- Kotlin学习笔记(八)对象
- Kotlin学习笔记3-9 类和对象-嵌套类
- 学习笔记:ES6之对象扩展
- Kotlin学习笔记3-4 类和对象-访问限制
- 我的kotlin学习笔记(一)——对象
- Kotlin学习笔记(七)【扩展】
- Kotlin学习笔记3-12 类和对象-委托