0

This is based off my last question Why am i getting a class cast exception(with generics, comparable)?

Here is my design again. I have an abstract super class, AbstractArrayList, and two concrete subclasses that extend it, sorted and unsorted array list.

Here's AbstractArrayList which manages the actual data because it needs to for the already implemented methods.

public abstract class AbstractArrayMyList<E> implements MyList<E> {
        protected E[] elementData;
       .....
}

Here is the declaration for ArrayListSorted, which extends AbstractArrayMyList

public class ArrayListSorted<E extends Comparable<E>> extends AbstractArrayMyList<E> 

And the lines of test code that caused the exception

    ArrayListSorted<Integer> toTestInteger = new ArrayListSorted<Integer>()
    toTestInteger.insert(0);
    assertEquals(toTestInteger.get(0).intValue(), 0);

And the actual exception itself

java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;
    at myarraylist.ArrayListSorted.getIndex(ArrayListSorted.java:38)

ArrayListSorted - java line 38 is inside this method

public int getIndex(E value) {
      ....
     line 38 - if      (value.compareTo(elementData[mid]) < 0)  hi = mid - 1;

The response I got from the question clarified what the exception was caused by. When I tried making this call

value.compareTo(elementData[mid]) < 0

value was of the correct type because the extends part will narrow the type object to Comparable type. However the JVM which runs the java bytecode, will only recognize the elementData array as an object array so when I am trying to cast elementData[mid] to Comparable, it's not actually of Comparable type.

The solution that chrylis gave me in the other question was to have a constructor in the AbstractArrayList that will construct the right typed array

protected AbstractArrayMyList(Class<E> clazz) {
        this.elementClass = clazz;
        this.elementData = Array.newInstance(clazz, INITIAL_SIZE);
}

I am trying to call this constructor in my sorted array list subclass, with

public class ArrayListSorted<E extends Comparable<E>> extends AbstractArrayMyList<E> 
       public ArrayListSorted() {
             super(Class.forName(("E"));
        }
   ...

Syntax I got from this thread - Passing a class as an argument to a method in java

However I get a compiler error - The constructor AbstractArrayMyList(Class) is undefined. Does anyone know what the issue is? I defined that same constructor that chrylis provided me in my question in AbstractArrayList that takes in a class instance.

Community
  • 1
  • 1
committedandroider
  • 8,711
  • 14
  • 71
  • 126
  • Hm, I think Class.forName("E") is wrong, or do you have such a class? This needs to be an existing one. In your case you most likely want a class argument to `ArrayListSorted(Class cls) { super(cls);}`. Your compile error is I think because `Class.forName(..)`` returns `Class>` not `Class` – eckes Jan 18 '15 at 19:44

3 Answers3

1

If you need the concrete class for a Parameter, you have to specify it. There is no way to derive it from the type parameter E.

This applies to your ArrayListSorted() constructor. If you want to keep ArrayListSorted generic (with a type Parameter), then you can only pass the Class object along. If you want to make it specific, you can just specify the parameter and the class.

In that case I would use a concrete class name like:

public class ArrayListSorted<E extends Comparable<E>>
  extends AbstractArrayMyList<E> {
   public ArrayListSorted(Class<E> cls) {
         super(cls);
    }
...

public IntArrayListSorted extends ArrayListSorted<Integer> {
  public IntArrayListSorted() {
    super(Integer.class);
  }
...

As you can see, when you specify the type parameter (... extends ArrayListSorted<Integer>) it will be defined as Integer, and then the constructor also expects a Class<Integer>: (super(Integer.class)).

One option is, to use a common interface as the implementation, so you can have:

public class ArrayListSorted<E extends Comparable<E>> extends AbstractArrayMyList<Comparable>
{
    public ArrayListSorted()
    {
        super(Comparable.class);
    }
}
eckes
  • 10,103
  • 1
  • 59
  • 71
0

No, not literally E, but the class you're using for E. See the constructor for EnumMap:

new EnumMap<>(KeyEnum.class)
chrylis -cautiouslyoptimistic-
  • 75,269
  • 21
  • 115
  • 152
0

You get the error "The constructor AbstractArrayMyList(Class) is undefined" because you don't have such a constructor.

public AbstractArrayMyList(Class<E> clazz)
{
    elementData=(E[])Array.newInstance(clazz);
}
Aaron
  • 874
  • 3
  • 17
  • 34