简单地说,交集类型是通过组合至少两种不同类型而创建的匿名类型的形式。
想象一下,我们需要模拟两种类型的动物:
我们可以简单地实现两个接口:
class SailfinFlyingfish implements Swimmable, Flyable {
@Override
public void fly() {
System.out.println("*flap flap*");
}
@Override
public void swim() {
System.out.println("*swim swim*");
}
}
|
但是,如果我们想要创建一种只接受可以游泳和飞行的动物的方法呢?
public static void process(... animal) {
animal.fly();
animal.swim();
}
|
变通方式是引入合成接口:
interface FlyableAndSwimmable extends Flyable, Swimmable { }
|
但这涉及相当多额外的样板代码,也不是很有弹性,但至少是类型安全的。
基于泛型的交叉类型(intersection type)
我们可以在定义泛型类型变量时使用该语法:
public static <T extends Flyable & Swimmable> void process(T animal) {
animal.fly();
animal.swim();
}
|
Java语言规范:
交叉类型采用T1&...&Tn(n> 0)的形式,其中Ti(1≤i≤n)是类型。
An intersection type takes the form T1 & … & Tn (n > 0), where Ti (1 ≤ i ≤ n) are types.
它可能看起来像一个基于泛型的黑客,但它实际上是一个完全成熟的合法Java功能 - 只是以一种有趣的方式实现。
通过利用这种语法,我们最终得到了一个类型安全和无样板解决方案。
自JDK10起
在JDK10之前,该方法只能在使用泛型类型参数时使用,但自从引入局部变量类型推理以来,我们可以在局部变量级别执行相同的操作:
var action = (Function<Integer, Integer> & Serializable) i -> i + 1;
|