3

为什么 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");
    }
}
4

2 回答 2

2

不同之处在于您在第一种情况下不使用方法的结果,但在第二种情况下使用。

演员表是一个表达式,但它不是一个StatementExpression。这意味着你不能这样写:

(String) somethingReturningAString();

但你可以写:

String aString = (String) somethingReturningAString();

在编译时,编译器checkcast会在它需要的地方以及它可以插入的地方插入指令:

  • 它不能为第一种情况插入强制转换,因此不会进行检查。
  • 它可以(并且必须)在第二种情况下插入强制转换,以确保它将实际上是 a 的东西分配给String变量String。因此,它检查演员表,但失败了。

值得注意的是,有一些可能出乎意料的情况,其中强制转换不是绝对必要的,而是插入的。例如:

Scratch.<String>getSomething(x -> "hello").toString();

会失败ClassCastException,因为它会被转换为:

((String) Scratch.getSomething(x -> "hello")).toString();

即使Object有一个toString()方法,所以它可以在没有强制转换的情况下调用它。

于 2019-05-31T12:43:43.697 回答
1

泛型只是编译时检查(阅读类型擦除)。所以在运行时,您的getSomething()方法看起来类似于:

static Object getSomething(Function fun) {
    return fun;
}

现在你清楚地看到第一行永远不会抛出异常

Scratch.getSomething(x -> "hello");

因为Function 一个Object,因此可以毫无问题地返回。

然而,第二行将抛出一个,因为它看起来类似于:

String something = (String) Scratch.getSomething(x -> "hello");

AFunction仍然是 a ,Object因此它可以从方法中返回,但它不是 a String,因此,你得到你的ClassCastException.

代码编译得很好,因为你告诉编译器你知道你在做什么。您将在此行收到Unchecked cast警告:

 return (T) fun;

该警告应该是编译器向您(程序员)发出的一个指示,表明它(编译器)无法确定该转换是否会成功。

于 2019-05-31T12:39:17.853 回答