扩展函数和属性
1.介绍
扩展:扩展一个类的新功能而无需继承该类或者使用像装饰者这样的设计模式,更多时候就是等价于java中静态函数。
fun String.changeChar() = this[0] //this对应这个字符串,并推导最后的类型,并返回
2.声明和this
声明一个扩展函数,我们需要用一个 接收者类型 也就是被扩展的类型来作为他的前缀。
隐含持有this,this表示接收者对象。
/**
* 这个 this 关键字在扩展函数内部对应到接收者对象(传过来的在点符号前的对象)
* 很容易理解,每个对象内部都有一个this指向自己,c++中也是如此
*
*/
/**
* 泛型
*/
fun <T> MutableList<T>.swap2(index1: Int, index2: Int) {
val tmp = this[index1] // “this”对应该列表
this[index1] = this[index2]
this[index2] = tmp
}
3.扩展函数优先级
扩展函数优先级最低,先调用原生的方法。
fun Any?.toString(): String {
if (this == null) return "null"
// 空检测之后,“this”会自动转换为非空类型,所以下面的 toString()
// 解析为 Any 类的成员函数
return toString()
}
4.扩展属性
注意:由于扩展没有实际的将成员插入类中,
//扩展函数,看起来和扩展属性相似,转换为java代码之后,发现确实几乎一致
fun <T> List<T>.lastIndex3(): Int = size - 1
val <T> List<T>.elements: List<T>
get() = (0 until size step 2).map { get(it) }
扩展作用域,等价于java中static函数
/**
* 扩展作用域
大多数时候我们在顶层定义扩展——直接在包里:
这句话不对,应该是跟所在类有关,如果是object或者没有声明class,则在包中,如果在类中,那么作用域就在类中
*/
案例如下:
package day3class
/**
* 在一个类内部你可以为另一个类声明扩展。
* 在这样的扩展内部,有多个 隐式接收者 —— 其中的对象成员可以无需通过限定符访问。
* 扩展声明所在的类的实例称为 分发接收者,扩展方法调用所在的接收者类型的实例称为 扩展接收者
*
* 相当于java中,一个类中含有另外一个类对象
* 作用域,只在Connection中
*/
class Host(val hostname: String) {
fun printHostname() {
print(hostname)
}
}
class Connection(val host: Host, val port: Int) {
fun printPort() {
print(port)
}
fun Host.printConnectionString() {
printHostname() // 调用 Host.printHostname()
print(":")
printPort() // 调用 Connection.printPort()
}
//对于分发接收者与扩展接收者的成员名字冲突的情况,扩展接收者优先。要引用分发接收者的成员你可以使用 限定的 this 语法。
fun Host.getConnectionString() {
toString() // 调用 Host.toString(),作用域在Host中,很容易理解,Host. 隐式的包含了一个this调用
this@Connection.toString() // 调用 Connection.toString()
}
fun connect() {
/*……*/
host.printConnectionString() // 调用扩展函数
}
}
fun main() {
Connection(Host("kotl.in"), 443).connect()
//Host("kotl.in").printConnectionString(443) // 错误,该扩展函数在 Connection 外不可用
//如果是object或者没有声明class,则在包中,如果在类中,那么作用域就在类中
}
5.扩展函数被子类继承
尽管扩展函数可以被继承,但是还是静态的,也就是根据类型调用,不具有多态的特性
ject或者没有声明class,则在包中,如果在类中,那么作用域就在类中
}
### 5.扩展函数被子类继承
```kotlin
尽管扩展函数可以被继承,但是还是静态的,也就是根据类型调用,不具有多态的特性