1.扩展原声API
为了声明一个函数扩展,我们需要在函数前加一个接收者类型作为前缀。下面我们
会为 MutableList 添加一个 swap 函数:
// 扩展:为类添加成员函数和属性
fun MutableList<Int>.swap(index1:Int, index2:Int)
{
val tmp = this[index1]
this[index1] = this[index2]
this[index2] = tmp
}
fun ArrayList<Int>.swap(index1:Int, index2:Int)
{
val tmp = this[index1]
this[index1] = this[index2]
this[index2] = tmp
}
fun main(args: Array<String>)
{
var mulableList = mutableListOf(1,2,3,4,5)
mulableList.swap(0,2)
println(mulableList)
var list:ArrayList<Int> = ArrayList()
list.add(20)
list.add(30)
list.add(40)
list.swap(0,2)
println(list)
}
扩展函数中的 this 关键字对应接收者对象。现在我们可以在任何
MutableList 实例中使用这个函数了
2.扩展自定义类
// 扩展自定义类
// 通过扩展在顶层添加的成员函数和属性无法在子类中重写,因为没有办法加open
open class MyParent(val value1:Int, val value2:Int)
{
var mValue1: Int = value1
var mValue2: Int = value2
fun add():Int
{
return mValue1 + mValue2
}
}
class MyChild(value1:Int, value2:Int):MyParent(value1, value2)
{
fun sub():Int
{
return mValue1 - mValue2
}
}
// 通过扩展向MyParent类添加一个printResult方法
fun MyParent.printResult()
{
println("${mValue1} + ${mValue2} = ${add()}")
}
// 通过扩展向MyChild类添加一个printResult方法
fun MyChild.printResult()
{
println("${mValue1} - ${mValue2} = ${sub()}")
}
fun main(args: Array<String>)
{
var parent1: MyParent = MyParent(1,3)
var parent2: MyParent = MyChild(1,3)
var parent3: MyChild = MyChild(1,3)
parent1.printResult()
parent2.printResult()
parent3.printResult()
}
输出结果:
1 + 3 = 4
1 + 3 = 4
1 - 3 = -2
3.成员函数冲突的解决方案
如果通过扩展向类中添加的成员函数与类中原来的成员函数的结构完全相同,那么内部成员函数优先
// 成员函数冲突的解决方案
// 如果发生冲突,在类中定义的函数优先级高
class MyClass
{
private var strValue:String = ""
constructor()
{
}
private constructor(str:String)
{
strValue = str
}
override fun toString(): String {
return strValue
}
fun newInstance(value:Int):MyClass
{
return MyClass("内部成员函数")
}
}
fun MyClass.newInstance(value:Int):MyClass
{
return MyClass()
}
fun main(args: Array<String>)
{
println(MyClass().newInstance(20))
}
输出:
内部成员函数
4. 扩展属性
和函数类似, Kotlin 也支持属性扩展:
val <T> List<T>.lastIndex: Int
get() = size-1
注意,由于扩展并不会真正给类添加了成员属性,因此也没有办法让扩展属性拥有
一个备份字段.这也是为什么初始化函数不允许有扩展属性。扩展属性只能够通过明
确提供 getter 和 setter方法来进行定义.初始化需要使用backing field,也就是field字段,可以将属性保存到field中,也可以从field中获取属性值
// 扩展属性
// 通过扩展添加的属性,不能使用field
class TestClass
{
var mValue:Int = 0
// 内部属性
var str:String = ""
get() = field // backing field字段
set(value)
{
field = value
}
}
var TestClass.value:Int
get() = mValue
set(value)
{
mValue = value
}
fun main(args: Array<String>)
{
var testClass = TestClass()
testClass.str = "hello"
testClass.value = 1000
println(testClass.str)
println(testClass.value)
}
5.扩展的范围
大多数时候我们在 top level 定义扩展,就在包下面直接定义:
package foo.bar
fun Baz.goo() { ... }
为了在除声明的包外使用这个扩展,我们需要在 import 时导入:
package com.example,usage
import foo.bar.goo // 导入所有名字叫 "goo" 的扩展
// 或者
import foo.bar.* // 导入foo.bar包下得所有数据
fun usage(baz: Baz) {
baz.goo()
}
6.在类中的扩展
前面的扩展都是写在顶层的,其实扩展也可以写在类中定义
// 在类中使用扩展
class D
{
fun bar()
{
println("D.bar")
}
}
class C
{
fun baz()
{
println("C.bar")
}
// 在C类中扩展D类
fun D.foo()
{
bar() // 调用D类的bar方法
baz() // 调用C类的baz方法
}
fun caller(d:D)
{
d.foo() // 调用扩展方法foo
}
}
fun main(args: Array<String>)
{
C().caller(D())
}
输出:
D.bar
C.bar