为什么main中的第一行不引发ClassCastException而第二行却引发ClassCastException?
import java.util.function.Function;
class Scratch {
static <T> T getSomething(Function<Integer, T> fun) {
return (T) fun;
}
public static void main(String[] args) {
Scratch.<String>getSomething(x -> "hello");
String something = Scratch.<String>getSomething(x -> "hello");
}
}
答案 0 :(得分:2)
区别在于,在第一种情况下,您不使用方法的结果,而在第二种情况下,您使用了方法的结果。
强制类型转换是表达式,但不是StatementExpression
。这意味着您不能这样写:
(String) somethingReturningAString();
但是您可以写:
String aString = (String) somethingReturningAString();
在编译时,编译器将checkcast
指令插入需要的位置以及可以插入的位置:
String
变量分配实际上是String
的内容。因此,它会检查演员表,但失败。值得注意的是,在某些情况下也许不是强制性强制强制转换,而是强制强制性强制转换已插入。例如:
Scratch.<String>getSomething(x -> "hello").toString();
失败的原因是ClassCastException
,因为它将被转换为:
((String) Scratch.getSomething(x -> "hello")).toString();
尽管Object
有一个toString()
方法,所以它可以在不进行强制转换的情况下调用它。
答案 1 :(得分:1)
泛型仅是编译时检查(有关type erasure的信息)。因此,在运行时,您的getSomething()
方法看起来类似于:
static Object getSomething(Function fun) {
return fun;
}
现在您可以清楚地看到第一行永远不会抛出异常
Scratch.getSomething(x -> "hello");
因为Function
是Object
,因此可以毫无问题地返回。
但是第二行 将抛出第一行,因为它看起来类似于:
String something = (String) Scratch.getSomething(x -> "hello");
Function
仍然是Object
,因此可以从方法中返回它,但它不是String
,因此,您得到了ClassCastException
。
代码可以很好地编译,因为您可以指示编译器您知道自己在做什么。您会在此行上收到Unchecked cast
警告:
return (T) fun;
此警告应该是编译器向程序员(即编译器)不能确保强制转换成功的指示。