Java:Instanceof 和泛型

新手上路,请多包涵

在查看我的通用数据结构以获取值索引之前,我想看看它是否甚至是类型 this 的实例已被参数化为。

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

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

这是错误消息:

无法对类型参数 E 执行 instanceof 检查。改用它的擦除对象,因为泛型类型信息将在运行时被擦除

更好的方法是什么?

原文由 Nick Heiner 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 943
2 个回答

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

你可以通过为你的对象创建一个工厂来捕获它:

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

然后在对象的构造函数中存储该类型,因此变量使您的方法看起来像这样:

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

原文由 Yishai 发布,翻译遵循 CC BY-SA 4.0 许可协议

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

选项 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 - 让它失败

如果您需要使用需要未知类型的抽象方法,那么您真正想要的只是让编译器停止抱怨 instanceof 。如果你有这样的方法:

 protected abstract void abstractMethod(T element);

你可以像这样使用它:

 public int indexOf(Object o) {

    try {

        abstractMethod((T) o);

    } catch (ClassCastException e) {

//...

您正在将对象转换为 T (您的泛型类型),只是为了愚弄编译器。 您的转换在运行时什么都不做,但是当您尝试将错误类型的对象传递到您的抽象方法时,您仍然会得到 ClassCastException。

注意 1:如果您在抽象方法中进行额外的未经检查的转换,您的 ClassCastExceptions 将在此处被捕获。这可能是好事,也可能是坏事,所以请仔细考虑。

注意 2: 当您使用 instanceof 时,您会得到一个免费的 null 检查。由于您不能使用它,因此您可能需要徒手检查是否为 null。

原文由 SharkAlley 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题