运算符重载和其他约定
- 通过调用自己代码定义函数,实现特定语言结构 比如在类中定义一个plug的方法,按照约定你就可以在该类实例中使用+ 运算符。
- 常见于把约定方法定义成拓展函数以适应现有的类。
data class Point(val x: Int, val y: Int)
operator fun Point.plus(other: Point) = Point(x + other.x, y + other.y) //使用拓展函数 签名必须加operator
在Kotlin中不能定义自己的运算符,提供的二元运算符有:
| 表达式 | 运算符 |
|---|---|
| b * A | times |
| a/b | devis |
| a%b | mod |
| a+b | plugs |
| a-b | minus |
Kotlin 运算符不会自动支持交互\
- 定义一个返回值结果不一样的运算符
operator fun Char.times(num: Int) = toString()+num //这里定义 左边是Char,右边是Int,返回结果是String值
//这里很明显是不能调换的。
- 重载符合赋值运算符 比如 +=
munisAssigntimeAssign+=可以用+号连接表示。
- 重载一元运算符
operator fun Point.unaryMinus() = Point(-x , -y )
//调用
println(-Point(10,10))//得到的结果 Point(-10,-10)
- 对应的一元运算符约定
| 表达式 | 函数名 |
|---|---|
| +a | unnaryPlus |
| -a | unnaryMunus |
| !a | not |
| ++a | inc |
| --a | dec |
-
重载比较运算符: “
equls”
a==b -> a?equls(b)?:(b==null) 恒等运算符=== 与Java中的“==” 是一样的。 -
排序运算符: compareTo 在Java中,这里这个排序算法用于查找最大值或者排序时候使用,必须要明确标记p1.compareTo(p2)<0,等价于Kotlin中p1<p2
data class Person(val name: String, val age: Int) : Comparable<Person> {
override fun compareTo(other: Person): Int {
return compareValuesBy(this, other, Person::name, Person::age)
}
}
集合和区间约定
- 使用下标访问元素“get”和“set” a[b] 下标运算符
val value = map[key]
也可以这样设置元素
mutablemap[key] = newValue
如果你需要实现一个二维矩阵可以这样写:
operator fun xx.get(rowIndex: Int,colIndex: Int)
//调用
xx[10,11]
- "in"的约定函数
contails
data class Rectangle(val upperLeft: Point, val lowerRight: Point)
operator fun Rectangle.contains(p: Point): Boolean {
return p.x in upperLeft.x until lowerRight.x &&
p.y in upperLeft.y until lowerRight.y
}
//调用
Point(10,10) in Rectangle(Point(2,2),Point(20,20))//true
- rangeTo的约定 区间约定..
public operator fun <T : Comparable<T>> T.rangeTo(that: T): ClosedRange<T> = ComparableRange(this, that)
val now = LocalDate.now()
println(now.plusDays(100) in now..now.plusWeeks(30))//true
(0..19).forEach { println("$it") }//也可以这样
- 在for循环中使用“iterator”的约定
for(x in list){/**逻辑**/}
in 被用于循环。for遍历字符串
for (letter in "abc") println("$letter")
可以自定义iterator方法,使用for遍历:比如遍历日期
operator fun ClosedRange<LocalDate>.iterator(): Iterator<LocalDate> = object : Iterator<LocalDate> {
var current = start
override fun hasNext() = current <= endInclusive
override fun next() = current.apply { current = current.plusDays(1) }
}
//调用
val now = LocalDate.now()
for (localDate in (now..now.plusDays(10))) {
println(localDate.atStartOfDay())
}
结构声明和组件函数
允许你展开单个复合值
data class Point(val x: Int, val y: Int)
val (x, y) = Point(10, 22)
println(x)//10
println(y)//20
需要用到约定原理,要在结果声明中初始化每一个变量,将调用名为componentN的函数,其中N是声明中的声明变量。
data修饰的class已经自动帮生成了这样的定义,所以不需要手动设置。使用场景:
从一个函数返回多个值,这个很有用。eg
data class NameComponent(val name: String, val extension: String)
fun getFileName(fullName: String): NameComponent{
val split = fullName.split('.', limit = 2)
return NameComponent(split[0],split[1])
}
//调用
val (fileName,extension) = getFileName("kotlin.txt")
println(fileName)//kotlin
println(extension)//txt
让一个函数返回多个值还可以用标准库中的Pair
在for循环中使用解构
val map = mapOf(2 to "11", 12 to "88", 0 to "99")//注意 标准库中,map是实现了component1,component2
//@kotlin.internal.InlineOnly
//public inline operator fun <K, V> Map.Entry<K, V>.component1(): K = key
//@kotlin.internal.InlineOnly
//public inline operator fun <K, V> Map.Entry<K, V>.component2(): V = value
for((key,value) in map){
println("key = $key,value = $value")
}
重用属性访问的逻辑:委托属性
- 操作对象不用自己执行,而是把工作委托给其他的一个辅助对象。称为:委托 一个标准的属性委托如下:
class foo {
private var delegate = Delegate()
var p: Type
get() = delegate.get
set(value) = delegate.set(value)
}
- 惰性初始化
by lazy()第一次访问该属性才会根据需要创建。跟单例的懒汉模式是一样的 使用标准库函数by lazy()会简洁很多
data class Person(val name: String, val age: Int) {
val emails by lazy { sendEmail(emails) }
}
- 通过
by关键字,编译器会自动生成委托的模版代码
Delegates.observable 函数可以用来添加属性更改的观察者。
//定义一个Person类
class Person(val name: String, age: Int, salary: Int) : PropertyChangeAware() {
val observer = { prop: KProperty<*>, oldValue: Int, newValue: Int -> changeSupport.firePropertyChange(prop.name, oldValue, newValue) }
var age :Int by Delegates.observable(age,observer)//Delegates.observable 函数可以用来添加属性更改的观察者。
var salary :Int by Delegates.observable(salary,observer)
}
//定义一个监听类
open class PropertyChangeAware {
protected val changeSupport = PropertyChangeSupport(this)
fun addPropertyChangeListener(listener: PropertyChangeListener) = changeSupport.addPropertyChangeListener(listener)
fun removePropertyListener(listener: PropertyChangeListener) = changeSupport.removePropertyChangeListener(listener)
}
//调用
val person = Person("Bob", 18, 20000)
person.addPropertyChangeListener(
PropertyChangeListener { evt ->
println("Property ${evt.propertyName} change from ${evt.oldValue} to ${evt.newValue}")
}
)
person.age = 19
- 在map中保存属性值
class Pepole {
private val _attributes = hashMapOf<String, String>()
fun setAttribute(attrName: String, value: String) {
_attributes[attrName] = value
}
val name: String by _attributes
}
框架中的委托属性
End