2

I'm trying to order a binary search tree, and store its values on an array, but when I try to convert my ArrayList to array it says I cannot convert an Object to Comparable.

@Override
public T[] postOrder() {
    ArrayList<T> array = new ArrayList<T>();
    postOrder(root, array);
    return (T[]) array.toArray();
}

private void postOrder(BSTNode<T> currRoot, ArrayList<T> array) {
    if (currRoot == null)
        return;
    if (!currRoot.getLeft().isEmpty())
        postOrder((BSTNode<T>) currRoot.getLeft(), array);
    if (!currRoot.getRight().isEmpty())
        postOrder((BSTNode<T>) currRoot.getRight(), array);
    array.add(currRoot.getData());
}

The error message: Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;

edit: solved that way

public T[] postOrder() {
    ArrayList<T> array = new ArrayList<T>();
    postOrder(root, array);
    return array.toArray((T[]) Array.newInstance(root.getData().getClass(), size()));
}
Gustavo Sousa
  • 45
  • 1
  • 8

2 Answers2

4

[Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;

This means you are trying to cast Object[] to Comparable[]. (The "[L" means array.)

toArray returns Object[]. You may be able to use <T>toArray(T[]) instead; however, due to type erasure you cannot do

//                  cannot do
//                    vvvvv
return array.toArray( new T[ mySize ] );

So either

  • Your tree needs a Class<T>.
  • The caller needs to pass a T[] to fill.
  • postOrder needs to return a non-generic array. (Object[]... Comparable[]...)
  • You should return a List<T> instead of a T[].

I notice you are using @Override so maybe your supertype (interface, superclass) has instructions on how to implement this method. (i.e. if this is homework you should ask your instructor because it is not clear to me which solution you should use.)

If you happen to have a Class<T>, then you can do

@Override
public T[] postOrder() {
    ArrayList<T> array = new ArrayList<T>();
    postOrder(root, array);
    return (T[]) array.toArray(
        java.lang.reflect.Array.newInstance(myClassT, array.size())
    );
}

Otherwise you need to change the signature of the method.

See also

Community
  • 1
  • 1
Radiodef
  • 35,285
  • 14
  • 78
  • 114
  • Great detailed explanation, but no solution... mine is the opposite :) – TWiStErRob Dec 06 '14 at 21:48
  • @TWiStErRob The OP is using `@Override` so they clearly can't change the method signature. Personally I am not really sure what to tell them. – Radiodef Dec 06 '14 at 21:49
  • I'm using `@Override` all over my code, but I also define the interfaces. Even if he can't modify the interface it's possible to pass in the `Class` instance in constructor like your referenced question does! – TWiStErRob Dec 06 '14 at 21:51
  • @TWiStErRob That's true, it could be the OP's own interface. – Radiodef Dec 06 '14 at 21:54
2

Generic arrays are messy, you need to call the other toArray() method:

public T[] postOrder(T[] result) {
    ArrayList<T> array = new ArrayList<T>();
    postOrder(root, array);
    return array.toArray(result);
}

It doesn't matter what size the result is, just make sure you don't use later what you passed in, because it may get reallocated inside toArray if the size is not correct, so use only the return value of postOrder.

Consider that it's probably much much more cleaner if you just return List<T>, and let the caller take care of converting it to an array! Notice how much less explanation is needed for returning a List...

public List<T> postOrder() {
    ArrayList<T> array = new ArrayList<T>();
    postOrder(root, array);
    return array;
}
TWiStErRob
  • 38,918
  • 20
  • 146
  • 220