Java 未经检查强制转换为类型参数警告,尽管是的实例

Java unchecked cast to type parameter warning despite being instance of

假设您有这个列表:

private final List<? extends AbstractXmlElement> inMemoryElements;

其中包含一堆 AbstractXmlElement 子类的对象,您想要添加一种方法来从该列表中过滤特定子类的对象。为此,我创建了以下方法:

public <E extends AbstractXmlElement> List<E> getInstancesOf(Class<E> c) {
    return getUsableElements().stream()
        .filter(c::isInstance)
        .map(e -> (E) e)
        .collect(Collectors.toList());
}

然而 (E) e 导致 UncheckedCast 警告。我想知道这究竟是一个未经检查的演员表,以及是否可以安全地抑制此警告,因为那些不是 E 实例的对象在演员表之前被过滤掉了。这意味着,据我所知,转换永远不会失败

how exactly this is an unchecked cast

您唯一的保证是 eAbstractXmlElement 的实例。但它可以是任何子类。因此,如果你有一个子类 AB 都扩展了 AbstractXmlElement,理论上类型约束意味着你可以尝试将 A 转换为 B,这会失败,如果您将 B.class 作为参数传递并且您的集合包含 A 的实例。因此警告。

请注意,编译器不会去检查您的过滤器表达式来确定只有 E 的实例才能通过过滤器;特别是它不会去阅读文档,然后还假设文档是正确的。据它所知,c::isInstance() 只是另一种采用 Object 并返回 boolean 的随机方法。那时没有任何迹象表明只有 E 的实例保留在流中通过过滤器。

if it is safe to suppress this warning

在这种情况下,是的。

这是一个未经检查的转换,因为 E 的类型是 unknown at runtime。由于您正在检查 isInstance(),因此您的代码是安全的。但是如果你想避免警告,你可以使用 c 来做演员:

.map(c::cast)