Вход/Регистрация
Философия Java3
вернуться

Эккель Брюс

Шрифт:

public class ListOfGenerics<T> {

private List<T> array = new ArrayList<T>;

public void add(T item) { array.add(item); } public T get(int index) { return array.get(index); } } ///:-

При этом вы получаете поведение массивов с безопасностью типов на стадии компиляции, возможной для параметризации.

Впрочем, иногда бывает нужно создать именно массив параметризованных типов (скажем, во внутренней реализации ArrayList используются массивы). Оказывается, можно переопределить ссылку так, чтобы предотвратить протесты компилятора. Пример:

II: tjenerics/ArrayOfGenericReference.java class Generic<T> {}

public class ArrayOfGenericReference { static Generic<Integer>[] gia:

} ///

Компилятор принимает эту запись без каких-либо предупреждений. С другой стороны, вы не сможете создать массив указанного типа (включая параметры типа), поэтому все это сбивает с толку. Поскольку все массивы обладают одинаковой структурой (размер каждого элемента и способ размещения в памяти) независимо от типа хранящихся данных, создается впечатление, что вы сможете создать массив Object и преобразовать его к нужному типу. Код отком-пилируется, но работать не будет — он выдает исключение ClassCastException:

II: generics/ArrayOfGeneriс.java

public class ArrayOfGeneriс {

static final int SIZE = 100, static Generic<Integer>[] gia; @SuppressWarni ngs("unchecked") public static void main(String[] args) {

// Компилируется, но приводит к ClassCastException:

//! gia = (Generic<Integer>[])new Object[SIZE];

II Тип времени выполнения является "стертым" type:

gia = (Generic<Integer>[])new Generic[SIZE];

System.out.pri ntin(gi a.getClass.getSi mpleName);

gia[0] = new Generic<Integer>;

//! gia[l] = new ObjectO; II Ошибка компиляции

II Обнаруживается несоответствие типов во время компиляции:

//! gia[2] = new Generic<Doublе>;

}

} /* Output:

Generic[]

*///:-

Проблема в том, что массивы отслеживают свой фактический тип, который задается в точке создания массива. Таким образом, даже несмотря на то, что gia преобразуется в Generic<Integer>[], эта информация существует только на стадии компиляции (а без директивы @SuppressWarnings вы получите предупреждение). Во время выполнения мы по-прежнему имеем дело с массивом Object, и это создает проблемы. Успешно создать массив параметризованного типа можно только одним способом — создать новый массив «стертого» типа и выполнить преобразование.

Рассмотрим чуть более сложный пример. Допустим, имеется простая параметризованная «обертка» для массива:

//: generics/GenericArray java

public class GenericArray<T> { private T[] array; @SuppressWarnings("unchecked") public GenericArray(int sz) {

array = (T[])new Object[sz];

}

public void put(int index, T item) { array[index] = item;

}

public T get(int index) { return array[index]; } // Метод, предоставляющий доступ к базовому представлению: public T[] rep { return array; } public static void main(String[] args) { GenericArray<Integer> gai =

new GenericArray<Integer>(10); // Приводит к ClassCastException: //! Integer[] ia = gai.rep: // А так можно. Object[] oa = gai.rep;

}

} ///:-

Как и прежде, мы не можем использовать запись Т[] array = new T[sz], поэтому мы создаем массив объектов и преобразуем его.

Метод гер возвращает Т[]; в методе main для gai это должен быть тип Integerf], но при попытке вызова и сохранения результата по ссылке на Integer[] будет получено исключение ClassCastException — это снова происходит из-за того, что фактическим типом объекта времени выполнения является Object[]. Если мы немедленно проводим преобразование к Т[], то на стадии компиляции фактический тип массива теряется и компилятор может упустить некоторые потенциальные ошибки. Из-за этого лучше использовать в коллекции Object[], а затем добавить преобразование к Т при использовании элемента массива. Вот как это будет выглядеть в примере GenericArray.java:

//: generics/GenericArray2.java

public class GenericArray2<T> { private Object[] array; public GenericArray2(int sz) { array = new Object[sz];

}

public void put(int index, T item) { array[index] = item;

}

@SuppressWarnings("unchecked")

public T get(int index) { return (T)array[index]; }

@SuppressWarnings("unchecked")

public T[] rep О { продолжение &

return (T[])array; // Предупреждение: непроверенное преобразование

}

public static void main(String[] args) { GenericArray2<Integer> gai =

new GenericArray2<Integer>(10); for(int i = 0: i < 10: i ++)

gai.put(i, i): for(int i = 0: i < 10; i ++)

System.out.print(gai.get(i) + " "); System.out.printlnO; try {

Integer[] ia = gai.rep; } catch(Exception e) { System.out.printin(e); }

}

} /* Output: (Sample)

0 12 3 4 5 6 7 8 9

java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer,

  • Читать дальше
  • 1
  • ...
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: