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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.