第30条款中有类似这样一段代码:
测试代码块1
public class GenericTest
{
private static UnaryOperator<Object> IDENTITY_FN= t->t;
@SuppressWarnings("unchecked")
public static <T> UnaryOperator<T> identityFunction() {
return (UnaryOperator<T>) IDENTITY_FN;
}
public void test1()
{
UnaryOperator<String> upString=identityFunction();
out.println(upString.apply("hehe"));
}
}
输出:
hehe
这样的代码为何能运行成功?
分析:
Java泛型推导机制,根据函数返回值能推断出T的类型,这行代码
UnaryOperator<String> upString = identityFunction();
让编译器推导出函数identityFunction中的泛型T是String类型,因此
return (UnaryOperator) IDENTITY_FN;
这行代码将一个List<Object> 转换成一个List<String>,但是为何能在运行时强制转换成功呢?
这要涉及Java泛型的实现方式,Java泛型是通过编译时擦除泛型信息来实现的,通过将上述代码编译后再反编译回来,可以看到泛型信息是怎么被擦除和使用的。
测试代码块2
public class GenericTest {
private static UnaryOperator IDENTITY_FN = (param1) -> {
return var0;
};
public static UnaryOperator identityFunction() {
return IDENTITY_FN;//并没有强制转换
}
public void test1() {
UnaryOperator var1 = identityFunction();
System.out.println((String)var1.apply("hehe"));//强制转换
}
}
可以看到,所有的泛型信息都没了,且并没有所谓的强制转换过程,UnaryOperator<l;String> 和UnaryOperator<Object>并没有区别,在这里都是UnaryOperator,而所有需要调用UnaryOperator<l;String>类的方法的地方,返回值都加了一个(String)的强制类型转换。
特别的,如果一个类中有一个T类型的属性,那么编译后会变为Object类型,并且在使用到它的地方,会加一个 (T) 这样的强制类型转换。