Java – ClassCastException when overriding the super method (Comparable)

ClassCastException when overriding the super method (Comparable)… here is a solution to the problem.

ClassCastException when overriding the super method (Comparable)

I did search but couldn’t find a similar issue. I’m sorry if this is a duplicate. I wrote a general queue method and tried to extend it to have a priority queue. I don’t understand why I can only insert when using methods in the parent (super class), not the code in the subclass, while storage[n] is Comparable and data is Comparable. If I try to do this in a subclass, a ClassCastException will be thrown. Am I doing something wrong?

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());
    }

}

Solution

You see this ClassCastExpression because in RegularQueue you are using the untyped safe assignment storage = (T[]) new Object[this.capacity]<. > regular queue as a type parameter of T. Therefore, at compile time it is known that this T must be Compatible or its subtype at runtime. Therefore, the compiler emits Comparable[] and forces this in PriorityQueue every time it accesses T[] storage.
The problem now is that storage is not actually of type T[], but only of type Object[], which leads to the ClassCastException you see. This happens when the field is accessed in any way, even if storage.length triggers it.

The

reason you don’t see this exception in insert is that the method call super.insert does not access storage directly.Only the super implementation does this, but does not perform any conversions, because the RegularQueue internal type T is unknown at compile time.

The solution is not to declare storage as T[], but to use Object[] because this is the actual type.

Others reported this to the JDK team as a bug, but the report was resolved (as expected) as “not an issue”. However, one of the JDK developers, Stuart Marks, was in delves into (probably better than this answer) the underlying problem in the report. I highly recommend reading it.

Related Problems and Solutions