抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

本篇文章以个人经历为引子进行闲谈,并不涉及什么原理

一、何为联合类型

当我学习Kotlin时,见到了一种奇怪的范型写法

fun <T, R> callMax(a: T, b: T): R where T: Comparable<T>, T:() -> R, R: Number

在Java里是这样的:

public static<T extends Comparable<T> & Supplier<T>, R extends Number> R callMax(T a, T b){}

这引起了我强烈的好奇,这个&是什么?
不难看出这里是“与”的关系,表示范型T只能是实现了Comparable<T>Supplier<T>两个接口的对象
具体来说就是联合类型,即把多个类型的特征结合起来形成的一种不真实存在的类型

部分人将其称为交集类型(Intersection type)

联合类型A & B可看作一个类型UU类型具有AB类型的共同的特征,相当于U继承自AB

二、如何在程序中使用

一句话总结:只能用于形参,不能用于实参,只是描述作用,不能当成正常的对象来使用

&符号可以一直连接,但连接时必须把类放在接口前
因为Java没有函数类型,所以只能借助接口或者类来间接实现这个联合的功能
比如下面这个例子:

class MyA {
public void t1(){
System.out.println("t1");
}
}

interface MyB {
public default void t2(){
System.out.println("t2");
}
}

class Combination extends MyA implements MyB {
public void t3(){
System.out.println("t3");
}
}

class MyC<T extends MyA & MyB> {
void t4(T t){
t.t1();
t.t2();// 变量t兼具MyA与MyB的方法
System.out.println("t4");
/*
* 不能调用t3,因为传进来的Combination对象
* 只是起一个描述MyA & MyB的作用,
* 并不是把Combination对象传进来了
*/
//t.t3();
}
}

public class TestClass {
public static void main(String[] args) {
// new MyC<MyA & MyB>(); 报错, 实参不能使用联合类型
MyC<Combination> myC = new MyC<>();// 通过间接实现和继承的方式是可以的
myC.t4(new Combination());// 也可以调用其内部的方法
}
}

最后的输出结果为:

t1
t2
t4

从上面这个例子可以看出来联合类型在Java联合类型的范型中的作用只能是描述,而非直接使用,我觉得原因在于Java会范型擦除,范型的类型无法保留下来,所以产生了这样奇奇怪怪的写法
我还在别人的文章中看到了这种使用方式
对lambda表达式进行强制类型转换:

public class Test {
public static void main(String[] args) {
Runnable job =(Runnable & Serializable) () ->System.out.println("Hello");
Class[] interfaces = job.getClass().getInterfaces();
for (Class i : interfaces) {
System.out.println(i.getSimpleName());
}
}
}

/*
Runnable
Serializable
*/

这也是一种很怪但又不是那么怪的写法,对于不知道这种形式的人来说根本看不大懂
不过根据前面学到的东西,这里联合类型其实也是起描述作用,而不能写在lambda表达式的括号(当作实参)里
目前了解的就这些了,范型擦除(伪范型)真是一个很神奇的东西呢~

评论