0

I am developing a big example case for teaching generics. A group of classes and interfaces that mimic the collections class in Java. Here's one of the source files:

package edu.brandeis.cosi12b.listdemo;

public class ArrayList<E extends Comparable<E>> extends AbstractList<E> implements List<E> {
  private E[] list;
  private int size;
  private int capacity;

  public ArrayList() {
    this(20);
  }

  @SuppressWarnings("unchecked")
  public ArrayList(int initialCapacity) {
    list = (E[]) (new Object[initialCapacity]);
    size = 0;
    capacity = initialCapacity;
  }

  public int capacity() {
    return capacity;
  }

  public int size() {
    return size;
  }

  public void add(E val) {
    list[size] = val;
    size++;
  }

  public String toString() {
    StringBuffer s = new StringBuffer();
    s.append("[");
    for (int i = 0; i < size - 1; i++) {
      s.append(list[i]);
      s.append(", ");
    }
    s.append(list[size - 1]);
    s.append("]");
    return (s.toString());
  }

  public void set(int index, E value) {
    expandIfNecessary(index);
    for (int i = size; i > index; i--) {
      list[i] = list[i - 1];
    }
    list[index] = value;
    if (index > size)
      size = index + 1;
  }

  @SuppressWarnings("unchecked")
  private void expandIfNecessary(int index) {
    if (index < capacity)
      return;
    int newCapacity = capacity * 2 + index;
    E[] oldArray = list;
    list = (E[]) (new Object[newCapacity]);
    for (int i = 0; i < size; i++)
      list[i] = oldArray[i];
    capacity = newCapacity;
  }

  public E get(int index) {
    if (index < 0 || index >= size)
      throw new ArrayIndexOutOfBoundsException("i: " + index + " s: " + size);
    return list[index];
  }

  public void remove(int index) {
    for (int i = index; i < size; i++)
      list[i] = list[i + 1];
    size--;
  }

  public boolean isEmpty() {
    return size() == 0;
  }

  public int indexOf(E value) {
    for (int i = 0; i < size; i++) {
      if (list[i] == value)
        return i;
    }
    return -1;
  }

  public boolean contains(E value) {
    return (indexOf(value) != -1);
  }

  @Override
  public void add(int index, E value) {
    // TODO Auto-generated method stub
  }
}

When I run this in a test case I get this error. I know it's something pretty subtle and it exceeds my knowledge of Java.

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;
    at edu.brandeis.cosi12b.listdemo.ArrayList.<init>(ArrayList.java:14)
    at edu.brandeis.cosi12b.listdemo.ArrayList.<init>(ArrayList.java:9)
    at edu.brandeis.cosi12b.listdemo.TestSuite.arrayListtest1(TestSuite.java:134)
    at edu.brandeis.cosi12b.listdemo.TestSuite.runArrayListTests(TestSuite.java:15)
    at edu.brandeis.cosi12b.listdemo.TestSuite.runAll(TestSuite.java:9)
    at edu.brandeis.cosi12b.listdemo.ListDemo.runTests(ListDemo.java:13)
    at edu.brandeis.cosi12b.listdemo.ListDemo.main(ListDemo.java:6)
1
  • The (E[]) (new Object[initialCapacity]) idiom is the sort of thing students will run in to lots of issues with. The other common issue is returning the E[] to the outside world which also throws an exception. Commented Apr 8, 2016 at 14:42

1 Answer 1

6

Use

list = (E[]) new Comparable<?>[initialCapacity];

and

list = (E[]) (new Comparable<?>[newCapacity]);

Java doesn't have fully reified generics at runtime (it uses erasure), so it doesn't actually know what E is - only that it extends Comparable, so that is what the compiler inserts for the casts.

The bytecode generated by the compiler for your code looks like this if decompiled:

list (Comparable[]) new Object[initialCapacity];

which fails.

Sign up to request clarification or add additional context in comments.

1 Comment

More technically, the erasure of a type variable is the erasure of its left-most bound. The erasure of a parameterized type is its raw type, so the erasure of <E extends Comparable<E>> is Comparable. docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.6

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.