2016-04-08 5 views
0

Я разрабатываю большой пример для обучения дженерикам. Группа классов и интерфейсов, которые имитируют класс коллекций в Java. Вот один из исходных файлов:Создание нового массива, содержащего Java Generics

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 
    } 
} 

Когда я запускаю это в тестовом примере, я получаю эту ошибку. Я знаю, что это что-то довольно тонкое, и это превышает мои знания 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) 
+0

'(E []) (новый объект [initialCapacity])' идиома - это то, с чем студенты будут сталкиваться с множеством проблем. Другая распространенная проблема заключается в возврате 'E []' во внешний мир, который также генерирует исключение. – Radiodef

ответ

6

Использования

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

и

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

Java не полностью реифицированные дженерик во время выполнения (он использует стирание), так что это на самом деле не знает, что E это - только то, что он расширяет Comparable, так что компилятор вставляет для прикладов.

Байткод, генерируемый компилятором для вашего кода выглядит следующим образом, если декомпилированы:

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

, который выходит из строя.

+2

Более технически стирание переменной типа является стиранием его самой левой границы. Стирание параметризованного типа является его сырым типом, поэтому стирание '>' является 'Comparable'. https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.6 – Radiodef

+0

Beautiful.Thanks. И так сложно ... – pitosalas