Question

This code works correctly and print out number 120. However, if I uncomment the line in the main function.

The code is throwing an exception: Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Comparable; cannot be cast to [Ljava.lang.Double; at General.main

I searched and found several discussion on generics array in java. People acknowledged the treatment of generics array is not very well in java. But I still feel very bad about this code: print out a line in different places will have different consequences, (execution correctly versus throw an exception).

Could someone please comment on this code and advise if there is any simple fix to the exception related to the println code in the main function?

Here is my code :

public class General<Key extends Comparable<Key>> {
    public Key[] keys;      
    @SuppressWarnings("unchecked")
    public General(int NMAX) {
        keys = (Key[]) new Comparable[NMAX];
        System.out.println(keys.length);
    }
    public static void main(String[] args){
    General<Double> g = new General<Double>(120);
    //      System.out.println(g.keys.length);
    }
}


System.out.println(g.keys.length);
Was it helpful?

Solution

The reason you get the exception in a seemingly strange place is because of erasure. Erasure of Key is Comparable so the cast here actually never happens at run time:

keys = (Key[]) new Comparable[NMAX];

But as you've observed, a cast does happen when you retrieve the array from outside the object. A Comparable[] is not a Double[] so you get the exception. As long as you don't access the array outside the class, the way you're doing it probably won't cause a problem.

The "safer" idiom is to make the array non-generic by making its declaration a Comparable[]. Then you:

  • Ensure that only Key can be put in the array.
  • Make the unchecked cast on a retrieval call.

Something like this:

@SuppressWarnings("rawtypes")
public class General<Key extends Comparable<Key>> {
    private Comparable[] keys;

    public General(int NMAX) {
        keys = new Comparable[NMAX];
    }

    public void set(int ind, Key k) {
        keys[ind] = k;
    }

    @SuppressWarnings("unchecked")
    public Key get(int ind) {
        return (Key)keys[ind];
    }
}

That's type safe and it's the way the JDK does it.

Another way is to have the client provide the array:

public class General<Key extends Comparable<Key>> {
    private Key[] keys;

    public General(Key[] keys) {
        this.keys = keys;
    }
}

You should also consider using a List instead because they do all this stuff for you and are fully generic. You can just do new ArrayList<Key>().

OTHER TIPS

You could try to keep the keys as a Comparable[] array.

public class General<Key extends Comparable<Key>> {
public Comparable[] keys;      // keys[i] = priority of i

public General(int NMAX) {
    keys = new Comparable[NMAX];
    System.out.println(keys.length);
}

public static void main(String[] args) {
    General<Double> g = new General<Double>(120);
    System.out.println(g.keys.length);
}
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top