Java中基于泛型的交叉类型 - {4Comprehension}


简单地说,交集类型是通过组合至少两种不同类型而创建的匿名类型的形式。
想象一下,我们需要模拟两种类型的动物:

  • 那些可以飞的
  • 那些可以游泳的

我们可以简单地实现两个接口:

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;