- 约束的定义
- 多个约束,where的使用
- 多个泛型参数
- 对比Java约束
一、约束的定义
当一个泛型参数没有任何约束时,它可以进行的操作和运算是非常有限的,因为不能对实参做任何类型上的保证,这时候就需要用到泛型的约束。泛型的约束是指泛型的实参必须满足一定的规范,编译器在编译的过程中可以根据约束来检查所有泛型类型的实参并确保其满足约束条件。
比如:我们定义一个通用类型的比较器,用于返回两个数据中的最大值。
- 没有约束条件下,代码可能是这样的
fun <T> ofMax(a: T, b: T): T = if (a > b) a else b
// 这时编译器会提示错误;
// Unresolved reference.
// None of the following candidates is applicable because of receiver type mismatch:
// public fun String.compareTo(other: String, ignoreCase: Boolean = ...):
// Int defined in kotlin.text
编译时编译器会提示错误,大体意思 a > b
这条语句编译器并不理解,需要通过下面 compareTo
类似的方法才能够让编译器知道这条语句的意思。那么我们给泛型加一个约束条件,要求T是实现Comparable
接口的子类,因为Comparable
中要求子类实现重载方法public operator fun compareTo(other: T): Int
,而编译器需要compareTo
方法才能知道如何比较 a 与 b 的大小;
- 有
Comparable
约束条件下的代码
fun <T: Comparable<T>> ofMax(a: T, b: T): T = if (a > b) a else b
测试代码运行效果:
fun main() {
println(ofMax(3, 5))
println(ofMax("abs", "kotlin"))
}
// 运行结果
5
kotlin
二、多个约束,where的使用
在我们实际开发中,有时会遇到一个泛型有多个约束条件的情况,比如两个数据既要比较大小,还要执行大的数据类型的invoke
方法,这时我们就要使用 where
关键字进行多个条件的约束。(如下面代码)
fun <T> ofMax(a: T, b: T)
where T : Comparable<T>, T : () -> Unit
= if (a > b) a() else b()
三、多个泛型参数
再比如开发中要求 比较两个T类型的数据大小,并调用大T的invoke方法,并返回一个R类型的数据,这时就要使用多个泛型参数了。(如下面代码)
fun <T, R> ofMax(a: T, b: T): R
where T : Comparable<T>, T : () -> R
= if (a > b) a() else b()
这里的泛型 R 也可以加上约束条件,比如必须是 数据类型 。
fun <T, R> ofMax(a: T, b: T): R
where T : Comparable<T>, T : () -> R, R : Number
= if (a > b) a() else b()
下面编写一个这样的案例,并运行验证
class EString(private val value: String) : Comparable<EString>, () -> Number {
override fun compareTo(other: EString): Int = value.compareTo(other.value)
override fun invoke(): Number = value.length
}
fun <T, R> ofMax(a: T, b: T): R
where T : Comparable<T>, T : () -> R, R : Number
= if (a > b) a() else b()
fun main() {
ofMax(EString("Java"), EString("Kotlin")).also(::println) // 6
}
四、对比Java约束
fun <T, R> ofMax(a: T, b: T): R
where T : Comparable<T>, T : () -> R, R : Number
= if (a > b) a() else b()
Java 中实现多泛型,多约束条件:
import kotlin.jvm.functions.Function0;
public class Generics {
public static class SString implements Comparable<SString>, Function0<Integer> {
private String value = "";
public SString(String value) { this.value = value; }
@Override
public int compareTo(SString other) { return this.value.compareTo(other.value); }
@Override
public Integer invoke() { return this.value.length(); }
}
public static <T extends Comparable<T> & Function0<R>,
R extends Number> R ofMax(T a, T b) {
if (a.compareTo(b) > 0) return a.invoke(); else return b.invoke();
}
public static void main(String[] args) {
SString a = new SString("Java");
SString b = new SString("Kotlin");
int result = ofMax(a, b);
System.out.println(result);
}
}
注意:Java 多约束条件使用 &
连接。