在java中,有一些特定的类与语言特性相关联,例如使用了iterable接口的对象可以在for循环中使用。

而在kotlin中,也有很多与语言特性相关的函数命名,对,他与java并不一样,他是选择了将功能和函数命名来绑定。
例如,如果在你的类中定义了一个名为 plus 的特殊方法,那么按照约定,就可以在该类的实例上使用+运算符。因此,在 Kotlin 中,我们把这种技术称为约定

约定

因为他并不是强依赖于类和他的继承关系。在kotlin中使用约定可以在类中重载其方法,也可以通过扩展函数去添加约定,从而适应现有的java类而不用修改其代码。

运算符重载

运算符重载所需要的关键词是operator,而且他所重载的方法都有特定的命名,都必须带上operator关键字。
这些表达式同样也满足+-/的基本运算规则。*

表达式 函数名
a * b times
a + b plus
a - b minus
a / b div
a % b mod
a * = b timesAssign
a + = b plusAssign
a % = b modAssign
a / = b divAssign
a - = b minusAssign
+ a unaryplus
- a unaryminus
! a not
a++,++a inc
a–,–a dec

如果从java中调用kotlin,那么可以很轻松的调用,因为每个重载的运算符都被定义为一个函数,可以像普通函数一样去调用。如果从kotlin调用java。java是不支持operator关键词的,只能写普通的函数,或者使用扩展函数来实现。

二元运算符

*kotlin中的这些运算符重载是不支持交换性的,也就是p1.5和1.5*p是两个东西,p1.5是在p的类中,定义了一个times方法,接受double参数。而1.5p就是在Double类中定义了一个times方法接受p类的参数。**

简单点说,就是他的顺序有限制,一般是前一个参数是本类,用来实现调用方法,后一个参数是接受的参数。

复合运算符

当你的代码中出现+=时,一般会plus和plusAssign都可以响应,编译器有可能报错。
通常情况下的解决办法是,plus都会返回一个新创建的类,所以一般用val去定义变量,直接用新地址去接受一个新变量。而plusAssign最好使用var,或者数组中相关的改变方法,这样才可以修改地址。

在某些时候,这两个都是可以同时调用的,因此建议只用一个

一元运算符

对于一元运算符,通常都是直接改变原值。而且对于他的++a,a++。kotlin库中也满足对应的顺序关系。

比较运算符

equals=====的关系:
在kotlin中的equals就是比较值的关系,他与==是等价的。也就是重写了equals方法就可以调用==这个运算规则。
===则是比较引用地址是否相同。

equals同样也是与==规则一致的,但是他并不需要写operator关键词,只需要写override?

因为equals这个方法是定义在Any类上,也就是所有的类都继承了equals方法,而他的operator关键词在Any中就定义了,所以我们不需要在写这个关键词,只需要添加上override表示重写即可。
还要注意,equals 不能实现为扩展函数,因为继承自 Any类的实现始终优先于扩展函数。

排序运算符


直接使用比较符号运算都会调用compareTo方法。

在Java 中,类可以实现 Comparable 接口,以便在比较的算法中使用,例如在查找最大值或排序的时候。接口中定义的compareTo方法用于确定一个对象是否大于另一个对象 但是在 Java 中,这个方法的调用没有简明语法。只有基本数据类型能使用 来比较,所有其他类型都需要明确写为elementl compare To(element2)
Kotlin 支持相同的 Comparable 接口。但是接口中定义的compare To 方法可以按约定调用,比较运算符(<,>,<=和>=) 的使用将被转换为 compareTo。

如果kotlin中实现了compareble接口,那么就可以直接重写compareTo而不使用operator关键字。

CompareValueBy是kotlin标准库中简洁的实现compareTo方法。。这个函数接收用来计算比较值的一系列回调,按顺序依次调用回调方法,两两一组分别做比较,并返回结果。而且这些回调可以使用lambda函数,如:

集合和区间的约定

  1. 通过集合下标访问元素
    他的本质就是调用了set和get方法。可以自己重写这些方法。而且你get,set方法可以与往常不一样,你还可以多设置几个参数,例如在二维数组的使用。operator fun get (rowindex: Int, colindex: Int ),然后用matrix [row,col ]来调用具体的值。
    set也是同理,只需要在相对应的get方法后,在多加一个value的参数即可。set 的最后一个参数用来接收赋值语句中(等号)右边的值,其他参数作为方括号内的下标

in的约定

当坚持一个对象是否属于某个集合时,或者类是否有继承关系时,就可以用in,他与contains方法相关联。返回一个Boolean值。

rangeTo 的约定


..会转化为rangeTo的函数。
如果

for循环中使用iterator的约定

如果是在for循环中,那么他使用的in运算符他就不是调用contains方法,而是调用iterator方法,他会自动的使用hasNext和Next方法。形成iterator的迭代。

解构声明和组件函数和循环


他的关键就是允许你在一个函数中需要返回多个值时,可以用一个对象把他们存起来,然后获得对象后,用结构声明把这个对象的属性分别导出来。而且他最多支持一个对象里最多五个属性再多的他也无法导出来。

在循环中的使用就是例如可以把map中的key和value同时导出来。for((key,value) in map)。这样的就会很便利。

委托属性:重用属性访问的逻辑

这个功能的基础是委托,他是一种设计模式。操作的对象不用执行,而是把工作委托给另一个辅助的对象。

我们通过在另一个委托类中,定义getValue和setValue方法来实现把一个属性的get和set方法都交给另个一类实现。
他有几个使用场景:

  1. 惰性初始化
    当我们初始化一个类时,如果直接把他所有的属性初始化完,会占用很大的内存。所以我们惰性初始化,只有当我们调用了get方法时,才会去完成初始化。

  2. 将逻辑都放到另一个类中统一处理。
    例如设置一个日志功能,使用set修改内容后,会打印修改内容。

    kotlin标准库中实现了一个类似的功能的类,你直接调用即可,而不用通过java去写他的具体实现。

  3. 实现细节