java - 重写 super 方法时的 ClassCastException (Comparable<T>)

标签 java generics comparable

我确实搜索过,但找不到类似的问题。如果这是重复的,我很抱歉。我编写了一个常规队列方法并尝试将其扩展为具有优先级队列。我不明白为什么我只能在使用父类(super class)的方法时插入,而不是子类中的代码,而 storage[n] 是 Comparable 而 data 也是 Comparable。如果我尝试在子类中这样做,将抛出 ClassCastException。我做错了什么吗?

RegularQueue.java

import java.util.Arrays;

public class RegularQueue<T> {

    protected int capacity;

    protected T[] storage;

    @SuppressWarnings("unchecked")
    RegularQueue(int capacity) {
        this.capacity = capacity;
        storage = (T[]) new Object[this.capacity];
    }

    @Override
    public String toString() {
        return "Queue{" +
                "capacity=" + capacity +
                ", storage=" + Arrays.toString(storage) +
                '}';
    }

    void insert(T data) {
        storage[0] = data;
    }
}

PriorityQueue.java

public class PriorityQueue<T> extends RegularQueue<Comparable<T>> {

    PriorityQueue(int capacity) {
        super(capacity);
    }

    // This doesn't work
    @Override
    void insert(Comparable<T> data) {
        storage[1] = data;
    }

    // ---> This works fine.
    //    @Override
    //    void insert(Comparable<T> data) {
    //        super.insert(data);
    //    }


    public static void main(String[] args) {
        PriorityQueue<Integer> q = new PriorityQueue<>(5);
        q.insert(1);
        System.out.println(q.toString());
    }

}

最佳答案

您看到此 ClassCastExpression 是因为在 RegularQueue 中您使用的是非类型安全赋值 storage = (T[]) new Object[this.capacity] .在 PriorityQueue 中,您使用的是 Comparable<...>作为 T 的类型参数常规队列。因此在编译时知道这个 T在运行时必须是 Comparable或者它的子类型。因此编译器发出 Comparable[]每次访问 T[] storage 时都会在 PriorityQueue 中转换强制执行此操作。
现在的问题是 storage实际上不是 T[] 类型但只有 Object[] 类型这导致您看到的 ClassCastException。以任何方式访问该字段时都会发生这种情况,即使是 storage.length触发它。

您在 insert 中没有看到此异常的原因方法调用 super.insert是它不直接访问storage .只有 super 实现会执行此操作,但不会执行任何转换,因为在 RegularQueue 内部类型为 T在编译时是未知的。

解决方案是不声明storage作为T[]而是使用 Object[]因为这是实际类型。

其他人将此作为错误报告给 JDK 团队,但报告已(如预期)作为“不是问题”得到解决。然而,JDK 开发人员之一斯图尔特·马克斯 (Stuart Marks) 在 his comment 中进行了解释在报告中深入(可能比这个答案更好)潜在的问题。我强烈推荐阅读它。

关于java - 重写 super 方法时的 ClassCastException (Comparable<T>),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63754170/

相关文章:

java - 是否可以显式使用 Java 内在锁?

C# - 以类型安全的方式将输入对象映射到效果对象

java - 不兼容的类型 : Node cannot be converted to Comparable (when passing as a parameter)

java - 如何将 ArrayList 的随机索引相互配对

java - 将 scala 类型规范更改为 java 类型规范

java - @OneToMany 映射列表大小限制

java - 为什么我们不能在 java 的普通方法中调用 this() 方法?

Java 8 泛型 : Reducing a Stream of Consumers to a single Consumer

java - 包装 Class<?> 类型泛型错误

swift - 在 Swift 4.2 中,如何编写 func<() 来比较类中的 3 个字段?