有和没有分配给变量的未经检查的强制转换行为
Unchecked cast behavior with and without assignment to variable
为什么 main 中的第一行不抛出 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");
}
}
泛型只是编译时检查(阅读 type erasure)。所以在运行时你的 getSomething()
方法看起来类似于:
static Object getSomething(Function fun) {
return fun;
}
现在你看清楚了,第一行永远不会抛出异常
Scratch.getSomething(x -> "hello");
因为 Function
是 一个 Object
因此可以毫无问题地返回。
但是第二行 将 抛出一个,因为它看起来类似于:
String something = (String) Scratch.getSomething(x -> "hello");
A Function
仍然是一个 Object
,所以它可以从方法返回,但它不是 String
,因此,你得到你的 ClassCastException
。
代码编译良好,因为您指示编译器您知道自己在做什么。您将在这一行收到 Unchecked cast
警告:
return (T) fun;
这个警告应该是编译器向你(程序员)发出的一个指示,它(编译器)不能确定转换是否成功。
不同之处在于,第一种情况下您不使用该方法的结果,而第二种情况下您使用该方法的结果。
强制转换是 表达式,但不是 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()
方法,因此它可以在没有转换的情况下调用它。
为什么 main 中的第一行不抛出 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");
}
}
泛型只是编译时检查(阅读 type erasure)。所以在运行时你的 getSomething()
方法看起来类似于:
static Object getSomething(Function fun) {
return fun;
}
现在你看清楚了,第一行永远不会抛出异常
Scratch.getSomething(x -> "hello");
因为 Function
是 一个 Object
因此可以毫无问题地返回。
但是第二行 将 抛出一个,因为它看起来类似于:
String something = (String) Scratch.getSomething(x -> "hello");
A Function
仍然是一个 Object
,所以它可以从方法返回,但它不是 String
,因此,你得到你的 ClassCastException
。
代码编译良好,因为您指示编译器您知道自己在做什么。您将在这一行收到 Unchecked cast
警告:
return (T) fun;
这个警告应该是编译器向你(程序员)发出的一个指示,它(编译器)不能确定转换是否成功。
不同之处在于,第一种情况下您不使用该方法的结果,而第二种情况下您使用该方法的结果。
强制转换是 表达式,但不是 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()
方法,因此它可以在没有转换的情况下调用它。