大师网-带你快速走向大师之路 解决你在学习过程中的疑惑,带你快速进入大师之门。节省时间,提升效率

kotlin中的二元运算符重载

可重载的二元算术运算符

表达式 函数名
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)都可以,所以这里产生歧义,编译器会报错
}