简单地说,交集类型是通过组合至少两种不同类型而创建的匿名类型的形式。
想象一下,我们需要模拟两种类型的动物:
我们可以简单地实现两个接口:
<b>class</b> SailfinFlyingfish implements Swimmable, Flyable { @Override <b>public</b> <b>void</b> fly() { System.out.println(<font>"*flap flap*"</font><font>); } @Override <b>public</b> <b>void</b> swim() { System.out.println(</font><font>"*swim swim*"</font><font>); } } </font>
但是,如果我们想要创建一种只接受可以游泳和飞行的动物的方法呢?
<b>public</b> <b>static</b> <b>void</b> process(... animal) { animal.fly(); animal.swim(); }
变通方式是引入合成接口:
<b>interface</b> FlyableAndSwimmable <b>extends</b> Flyable, Swimmable { }
但这涉及相当多额外的样板代码,也不是很有弹性,但至少是类型安全的。
基于泛型的交叉类型( intersection type )
我们可以在定义泛型类型变量时使用该语法:
<b>public</b> <b>static</b> <T <b>extends</b> Flyable & Swimmable> <b>void</b> 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之前,该方法只能在使用泛型类型参数时使用,但自从引入局部变量类型推理以来,我们可以在局部变量级别执行相同的操作:
<b>var</b> action = (Function<Integer, Integer> & Serializable) i -> i + 1;