Java:Instanceof 和 Generics

2022-08-31 07:20:18

在查看值的索引的泛型数据结构之前,我想看看它是否甚至是已参数化到的类型实例。this

但是当我这样做时,Eclipse抱怨道:

@Override
public int indexOf(Object arg0) {
    if (!(arg0 instanceof E)) {
        return -1;
    }

这是错误消息:

无法针对类型参数 E 执行实例检查。请改用其擦除对象,因为泛型类型信息将在运行时被擦除

更好的方法是什么?


答案 1

错误消息说明了一切。在运行时,类型消失了,没有办法检查它。

你可以通过为你的对象创建一个工厂来抓住它,如下所示:

 public static <T> MyObject<T> createMyObject(Class<T> type) {
    return new MyObject<T>(type);
 }

然后在对象的构造函数中存储该类型,因此变量,以便您的方法可以如下所示:

        if (arg0 != null && !(this.type.isAssignableFrom(arg0.getClass()))
        {
            return -1;
        }

答案 2

使用泛型进行运行时类型检查的两个选项:

选项 1 - 损坏构造函数

假设您正在覆盖 indexOf(...),并且只想检查类型的性能,以节省自己迭代整个集合的时间。

像这样制作一个肮脏的构造函数:

public MyCollection<T>(Class<T> t) {

    this.t = t;
}

然后,您可以使用 isAssignableFrom 来检查类型。

public int indexOf(Object o) {

    if (
        o != null &&

        !t.isAssignableFrom(o.getClass())

    ) return -1;

//...

每次实例化对象时,您都必须重复自己:

new MyCollection<Apples>(Apples.class);

你可能会认为这是不值得的。在ArrayList.indexOf(...)的实现中,它们不检查类型是否匹配。

选项 2 - 让它失败

如果你需要使用一个需要未知类型的抽象方法,那么你真正想要的就是编译器停止为实例而哭泣。如果你有这样的方法:

protected abstract void abstractMethod(T element);

你可以这样使用它:

public int indexOf(Object o) {

    try {

        abstractMethod((T) o);

    } catch (ClassCastException e) {

//...

您将对象强制转换为 T(您的泛型类型),只是为了欺骗编译器。您的强制转换在运行时不执行任何操作,但是当您尝试将错误类型的对象传递到抽象方法中时,您仍然会得到一个 ClassCastException。

注意 1:如果您在抽象方法中执行其他未经检查的强制转换,则 ClassCastExceptions 将被捕获到此处。这可能是好的,也可能是坏的,所以仔细想想。

注意 2:使用 instanceof 时,您将获得免费的空检查。由于您无法使用它,因此您可能需要徒手检查空值。