【问题标题】:Unchecked cast behavior with and without assignment to variable未检查的强制转换行为有和没有分配给变量
【发布时间】:2019-10-17 02:33:57
【问题描述】:

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

【问题讨论】:

  • 无法回答问题,但您显然正在尝试将 Function 转换为 String,这不太可能奏效。需要在某处调用 fun.apply。
  • 因为你在第二种情况下使用了结果,而不是在第一种情况下。

标签: java generics unchecked-exception


【解决方案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;

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

【讨论】:

    【解决方案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() 方法,所以它可以在没有强制转换的情况下调用它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-03
      • 1970-01-01
      • 2023-03-10
      • 2013-05-11
      • 1970-01-01
      相关资源
      最近更新 更多