可重载的二元算术运算符
表达式 | 函数名 |
---|---|
a*b | times |
a/b | div |
a%b | rem |
a+b | plus |
a-b | minus |
在kotlin中,重载运算符需要使用operator修饰符,如
data class KtOperator(private var num: Int) {
operator fun plus(ktOperator: KtOperator): KtOperator {
return KtOperator(num + ktOperator.num)
}
}
在java中调用时,像使用普通函数即可,如
public static void main(String[] args) {
KtOperator ktOperator1 = new KtOperator(1);
KtOperator ktOperator2 = new KtOperator(3);
System.out.println(ktOperator1.plus(ktOperator2));
}
当从Kotlin调用Java的时候,对于与Kotlin约定匹配的函数都可以使用运算符语法来调用,由于Java没有定义任何用于标记运算符函数的语法,所以使用operator修饰符的要求对它并不适用,唯一的约束是,参数需要匹配名称和数量,如
public class JavaOperator {
private int num;
public JavaOperator(int num) {
this.num = num;
}
@Override
public String toString() {
return "JavaOperator{" +
"num=" + num +
'}';
}
public JavaOperator plus(JavaOperator javaOperator) {
return new JavaOperator(num + javaOperator.num);
}
}
在kotlin中调用
fun main(args: Array<String>) {
val javaOperator1 = JavaOperator(1)
val javaOperator2 = JavaOperator(1)
println(javaOperator1 + javaOperator2)
}
对于+=这样的广义赋值操作符,我总结了一下有这样的问题,当你在代码中用到+=的时候,理论上plus和plusAssign都可能被调用,如果在这种情况下,两个函数都有定义且适用,编译器会报错.
当遇到+=的时候,系统会这样来判断:
- 广义赋值操作符的返回值类型必须为 Unit,否则定义的时候系统会提示错误
- 如果执行 a += b 时 plusAssign 不存在,会尝试生成 a = a + b,其中的 a + b 使用的就是 plus 操作符方法,相当于调用 a = a.plus(b)。并且此时会 要求 a + b 的 plus 方法的返回值类型必须与 a 类型一致(如果单独使用 a + b 不做此要求)。
- 如果执行 a += b 时 plusAssign 存在,对应的二元算术运算符函数也可用,并且a是var则报错,因为这时候既可以调用 a = a + b,也就是 a = a.plus(b),又可以调用 a.plusAssign(b),它们都符合操作符重载约定,这样就会产生歧义。而如果使用 val 定义 a,则只可能执行 a.plusAssign(b),因为 a 不可被重新赋值,因此 a = a + b 这样的语法是出错的,永远不能被调用,那么调用 a += b 就不会产生歧义了。(plus 对应 plusAssign。minus、times 等也类似。)
下面给出一个例子:
fun main(args: Array<String>) {
val list1 = listOf(1, 2, 3)
list1 + 1
list1 += 1//error
//上面的错误是因为list1是List对象,该对象没有plugAssign方法,所以会尝试生成list1 = list1 + 1,而list1是val的,所以这里报错
var list3 = listOf(1, 2, 3)
list3 + 1
list3 += 1//right
//上面正确是因为list3是List对象,该对象没有plugAssign方法,所以会尝试生成list1 = list1 + 1,而list1是var的,所以这里正确
val list2 = arrayListOf(1, 2, 3)
list2 + 1
list2 += 1//right
//上面正确是因为list2是ArrayList对象,该对象有plugAssign方法,但是因为list2是val的,所以这里只能调用plugAssign方法
var list4 = arrayListOf(1, 2, 3)
list4 + 1
list4 += 1//error
//上面是错误的是因为list4是ArrayList对象,该对象有plugAssign方法,但是因为list2是var的,所以这里调用list4.plus(1)和list4.plusAssign(1)都可以,所以这里产生歧义,编译器会报错
}