五、多态和扩展
1、重载算术运算符
算术运算符最能直观的反映kotlin的约定。在kotlin中,可以使用+=等基本运算符对集合或者对象进行操作。
data class Point(val x:Int,val y:Int) {
//使用operator关键字声明plus函数
//用于重载运算符的所有函数都需要用它标记,表示约定而不是同名函数
operator fun plus(other:Point): Point {
//坐标分别相加返回新的Point
return Point(x+other.x,y+other.y)
}
}
val p1 = Point(10, 20)
val p2 = Point(20, 30)
//等同 p1.plus(p2)
println(p1 + p2) //Point(x=30, y=50)
也可以定义为扩展函数
//定义名为plus方法
operator fun Point.plus(other:Point): Point {
//坐标分别相加返回新的Point
return Point(x+other.x,y+other.y)
}
使用扩展函数来定义约定是常用的模式。
在kotlin中不能定义自己的运算符。kotlin限定了重载的运算符且需要在类中定义对应名字的函数。
2、扩展:为别的类添加方法和属性
1、扩展函数:你只需要在你添加的函数名字之前放置你想要扩展的类或者接口的类型。这个类名叫着接收器类型(receiver type),而你调用的扩展函数的值叫做接收器对象(receiver object)。如下图:
接收器类型是扩展定义的类型,而接收器对象是这个类型的实例。调用方式跟普通的函数调用方式一致:
println("Kotlin".lastChar())
2、作用域
将扩展函数直接定义在包内,使用他的地方直接import调用即可,类似于static调用。
如果将扩展函数定义在class里边,则他的作用域只在该类或者该类的子类里调用。
扩展函数是类外部非函数不能被覆盖
可能你引入的第三方包都对同一个类型进行了相同函数名扩展,为了解决冲突问题,你可以使用as的方式对扩展函数进行改名。
import com.dengyin2000.kotlintest1.lastChar as last
fun main(args: Array<String>) {
println("Kotlin".last())
}
3、泛型化的扩展函数
fun String.lastChar(): Char = this.get(this.length - 1)
fun <T> Collection<T>.joinToString(
separator: String = ",",
prefix: String = "",
postfix: String = ""
): String{
val result = StringBuilder(prefix)
for ((index, value) in this.withIndex()) {
if (index > 0) {
result.append(separator)
}
result.append(value)
}
result.append(postfix)
return result.toString()
}
fun main(args: Array<String>) {
println(listOf("a", "b", "c").joinToString(prefix = "[", postfix = "]"))
}
输出:[a,b,c]
4、扩展属性
扩展属性是给属性提供了一个能通过API来进行访问的拓展,扩展属性没有默认值,只能通过api来进行计算。
示例:
val String.lastChar: Char
get() = get(length - 1)
var StringBuilder.lastChar: Char
get() = get(length - 1)
set(value) {
this.setCharAt(length -1, value)
}
fun main(args: Array<String>) {
println("Kotlin".lastChar)
val sb = StringBuilder("Kotlin")
sb.lastChar = 'g'
println(sb)
}
5、静态扩展函数
在kotlin要声明一个静态扩展函数,必须得用伴生对象,那么引用的时候就得用对象去引用扩展函数,假设类中已经有一个伴生对象,如果我们不想在类中定义扩展函数,那么在类的伴生对象上可以这么写: fun 类.companion.foo(){ print(“hi”) },这样我们就可以在没有类的实例的情况下调用这个扩展函数了,类.foo()
6、同名的类成员的方法的优先级总高于同名的扩展函数。
7、标准库的扩展函数
除了之前说的with、apply之外,还有run let also takeIf
class TestBean {
var name: String = "siry"
var age: Int = 18
var sex: String = "girl"
fun setData(name: String = "lily", age: Int = 18, sex: String = "girl") {
}
}
run函数:函数内使用this代替本对象
###返回值为函数最后一行或者return指定的表达式
var result = testBean.run {
Log.i("LHD", "run 函数 this = " + this)//this代表当前testBean对象
// it run函数无法使用it但可以使用this来指代自己
this?.age = 17
this?.age//返回这行
}
Log.i("LHD", "run 的返回值 = $result")
let函数:函数内使用it代替本对象
返回值为函数最后一行或者return指定的表达式
var result2 = testBean.let {
//let 函数可以使用it
Log.i("LHD", "it = $it")//it代表当前testBean对象
// Log.i("LHD", "let 函数 = " + this)//this代表Mainactivity
it?.age = 16//这行其实是在调用setAge函数,如果这行为最后一行,则没有返回值
it?.age//返回这行
}
Log.i("LHD", "let 返回值 = $result2")
also函数:函数内使用it代替本对象,返回值为本对象
var result4 = testBean.also {
it?.age = 14
}
Log.i("LHD", "also 返回值 = $result4")
takeIf函数:条件为真返回对象本身否则返回null
testBean?.age = 18
//age = 18
var resultTakeIf = testBean?.takeIf {
it.age > 15//这个条件判断为真返回对象本身否则返回null
}
var resultTakeIf2 = testBean?.takeIf {
it.age < 15//这个条件判断为真返回对象本身否则返回null
}
8、Android中的扩展函数得慎用,比如Context类的扩展避免引起不必要的内存泄漏。
更多学习
kotlin基础语法(学习笔记一) |
kotlin面向对象(学习笔记二) |
kotlin面向对象(学习笔记三) |
kotlin面向对象(学习笔记四) |
关注我获取更多知识或者投稿
如有任何疑问可在文章底部留言。为了防止恶意评论,本博客现已开启留言审核功能。但是博主会在后台第一时间看到您的留言,并会在第一时间对您的留言进行回复!欢迎交流!
本文链接: https://leetcode.jp/kotlin多态和扩展(学习笔记五)/