泛型集合中的 ClassCastException 与 instanceOf

ClassCastException vs instanceOf in Generic Collections

我有一个 class 实现了 Collection<E>

当我检查我的集合是否包含一个项目时,接口的方法给出一个对象参数,当它必须是一个 <E>

你觉得写这段代码"normal"吗:

@Override
public boolean contains(Object o)
{
    E item;
    try
    {
        item=(E) o;
    }
    catch (ClassCastException e)
    {
        return false;
    }
    //check if contains "item"
}

我知道通常使用 try,catch 检查对象的类型是一个糟糕的主意,但在通用集合中我无法使用 instanceOf 检查并且我找不到更好的解决方案。

你可以在这个方法中抛出ClassCastException,所以你不能检查类型。阅读 Collection 接口的 javadoc。

恕我直言,您应该使用参数对象的 equals / hashCode 方法来检查它是否存在于您的集合中。根本不需要转换或 instanceof。

javadoc 它说:

Throws: ClassCastException - if the type of the specified element is incompatible with this collection (optional)

所以完全可以这样编码:

    @Override
    public boolean contains(Object o) {
        T item = (T) o;
        // ...
    }

如果转换失败则抛出 ClassCastException

您当然应该 隐藏该异常并安静地 return false - 这可能会在用户代码中留下许多潜在的错误。

如果您的集合 class 具有 E 作为无边界的通用类型参数,您的检查将毫无用处 -- 强制转换不可能失败,因为完全没有检查演员阵容。 E,如果它是无界的,则被擦除为 Object,你的演员表将是 item=(Object) o;,这不会失败。它可能会导致其他地方的其他失败,但它不能在这里失败,如果以后在其他地方失败,你的 try-catch 也不会捕获它。

你不能使用 instanceof 的事实应该告诉你一些事情 -- instanceof 不能使用的原因是因为它是运行时检查,需要 class在运行时进行检查,而您在运行时没有 class。尝试让演员表失败也是一种运行时检查,因此它根本不会改善您的情况。依靠强制转换失败仅在与 instanceof 相同的情况下有效,因此 NEVER 对 "use a cast because instanceof doesn't work".

有意义

编写通用代码时,重要的是要考虑代码在类型擦除后的外观。当您将泛型代码擦除为非泛型代码时(通过在适当的地方添加强制转换),代码应该可以正常工作。如果不能将代码写成非泛型,那么它也不能写成泛型。

@Override
public boolean contains(Object o)
{
    Object item;
    try
    {
        item= o;
    }
    catch (ClassCastException e) // does this make sense?
    {
        return false;
    }
    //check if contains "item"
}