【问题标题】:Unchecked cast: 'java.lang.Object[]' to 'T[]' [duplicate]未经检查的演员表:'java.lang.Object[]' 到 'T[]' [重复]
【发布时间】:2020-07-29 16:45:11
【问题描述】:

我有以下方法:

public static <T> T[] toArray(Iterable<? extends T> iterable) {
  return (T[]) StreamSupport.stream(iterable.spliterator(), false).toArray();
}

我的 IDE 告诉我有一个未经检查的演员表。 一般来说,我理解错误消息,但我不明白为什么要检查强制转换,因为可迭代的类型与我用于强制转换的类型相同。有人可以向我解释一下吗?

【问题讨论】:

  • 嘿!你为什么要做&lt;? extends T&gt; 而不仅仅是&lt;T&gt;
  • 这不是让整个事情更加面向未来吗?
  • 不,为什么它会“面向未来”?你知道? extends T 做什么吗?如果用Animal[] as = toArray(some Iterable&lt;Dog&gt;)Dog[] as = toArray(some Iterable&lt;Animal&gt;)Dog[] as = toArray(some Iterable&lt;Dog&gt;) 调用此方法会发生什么?它们中的哪一个有效,为什么并且是期望的?
  • 这里没有“未来证明”。它的作用是,它允许某人做Animal[] animals = toArray(dogs),其中dogs 是,例如List&lt;Dog&gt;。这是有道理的,但是,因为数组是协变的,所以不需要它。因此,如果您将其保留为T,您将返回一个Dog[],它也可以分配给Animal[],因为它是协变的。所以在这种情况下,通配符? extends T 是不必要的。
  • 我知道你在说什么。我一直在寻找其他实现,番石榴也使用它:link。有什么区别?

标签: java generics


【解决方案1】:

但我不明白为什么要检查演员表

检查强制转换是导致checkcast 字节码指令的东西。例如:

String s = (String) someObject;

在泛型的情况下,不能插入checkcast 指令,因为此时代码中没有已知类型:checkcast 检查的类型被静态写入字节码;但您的方法必须适用于 所有 类型。因此这里不能添加checkcast

警告是编译器表示“我不能确定,但​​这里看起来有点可疑”的方式。而且,确实存在一些可疑之处,但此代码中并未出现问题。

假设你这样称呼这个方法:

Integer[] ints = toArray(iterableOfInts);

实际上会在调用站点插入一个检查演员表(由编译器插入):

Integer[] ints = (Integer[]) toArray(iterableOfInts);

这将在运行时失败,因为 Object[] 无法转换为 Integer[]。但是失败发生在here,而不是在toArray 方法中。

解决这个问题的正确方法是提供一些东西来创建T[]

public static <T> T[] toArray(Iterable<? extends T> iterable, IntFunction<T[]> arraySupplier) {
  return StreamSupport.stream(iterable.spliterator(), false).toArray(arraySupplier);
}

Iterable&lt;? extends T&gt; 是一个合适的参数类型,因为它可以让你创建一个超类型的数组:

Integer[] integers = toArray(iterableOfInts, Integer[]::new);
Object[] objects = toArray(iterableOfInts, Object[]::new);

【讨论】:

    猜你喜欢
    • 2017-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-06
    • 1970-01-01
    • 2010-09-20
    相关资源
    最近更新 更多