java - 使用 Java-8 时可变参数中的 ClassCastException

标签 java generics exception java-8

以下代码对于 m2() 工作正常,但当我使用 m1() 时抛出 ClassCastException

m1m2 之间的唯一区别是参数数量。

public class Test  {

  public static void m1() {
        m3(m4("1"));
    }

    public static void m2() {
        m3(m4("1"), m4("2"));
    }

    public static void m3(Object... str) {
        for (Object o : str) {
            System.out.println(o);
        }
    }

    public static <T> T m4(Object s) {
        return (T) s;
    }

    public static void main(String[] args) {
        m1();
   }
 }

我的问题是 - 当我们使用泛型时,可变参数不适用于单个参数吗?

PS:这与 ClassCastException using Generics and Varargs 无关

最佳答案

让我们暂时跳过您忽略了未经检查的转换警告的事实,并尝试理解为什么会发生这种情况。

在此声明中:

Test.m3(Test.m4("1"));

有一种推断类型,即m4的返回类型。如果要在 m3 调用上下文之外使用它,如下所示:

Test.m4("1"); // T is Object

T 被推断为 Object。可以使用类型见证来强制编译器使用给定类型:

Test.<String>m4("1"); // T is String

...或者通过在赋值上下文中使用表达式:

String resString = Test.m4("1"); // T is String
Integer resInt = Test.m4("1"); // T is Integer <-- see the problem?

...或在调用上下文中:

Integer.parseInt(Test.m4("1")); // T is String
Long.toString(Test.m4("1")); // T is Long

现在,回到 Test.m3(Test.m4("1"));:我找不到这方面的引用,但我相信编译器被迫生成 T解析为m3的参数类型,即Object[]。这意味着 必须m3 的参数类型一致的 T 因此被解析为 Object[],这使得您将泛型类型指定为:

Test.m3(Test.<Object[]>m4("1")); // this is what is happening

现在,因为 m4 没有返回 Object[],所以 m3 正在接收 String,这导致不可避免的ClassCastException

如何解决?

解决此问题的第一种方法是为 m4 指定正确的类型参数:

Test.m3(Test.<String>m4("1")); 

这样,String 就是 m4 的返回类型,并且使用单个 String 调用 m3对象(对于 Object... var-arg),就像您编写的一样:

String temp = m4("1");
m3(temp);

@Ravindra Ranwala 已删除的答案中建议了第二种方法。在我看来,这可以归结为注意编译器警告:

public static <T> T m4(Object s) {
    return (T) s; // unchecked cast
} 

未经检查的强制转换警告只是告诉您编译器(和运行时)不会强制执行类型兼容性,只是因为 T 不知道您在哪里进行强制转换。以下版本是类型安全的,但它也使编译器使用 String 作为 m4 的返回类型以及 m3< 的参数类型:

public static <T> T m4(T s) {
    return s;
}

这样,m3(m4("1"));仍然使用Object...作为m3的参数类型,同时保留 String 返回类型为 m4(即,字符串值用作 Object 数组的第一个元素)。

关于java - 使用 Java-8 时可变参数中的 ClassCastException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59386790/

相关文章:

java - 由于 eclipse.ini,Eclipse 未运行

java - 使用预定义库在 Java 中生成 4 位唯一随机数?

java - JSlider 未在空布局 JPanel 上绘制

c# - 在通用目标上动态调用方法

c# - 类型初始化器(静态构造器)异常处理

java - 尝试加载 URL 时发生太多重定向 <-- 没有任何重定向

c# - 如何实现通用 IEnumerable 或 IDictionary 以避免 CA1006?

C# 泛型,状态模式的交叉引用类

c# - 如何创建一个可以在 C# 中的任何异常上执行的方法?

c++ - 抛出非异常对象