运算符重载和其他约定
- 通过调用自己代码定义函数,实现特定语言结构 比如在类中定义一个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值
//这里很明显是不能调换的。
复制代码
- 重载符合赋值运算符 比如 +=
munisAssign
timeAssign
+=可以用+号连接表示。
- 重载一元运算符
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