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

Эккель Брюс

Шрифт:

На первый взгляд почти ничего не изменилось, разве что преобразование типа было перемещено. Без директив @SuppressWarnings вы по-прежнему будете получать предупреждения, но теперь во внутренней реализации используется Object[] вместо Т[]. При вызове get объект преобразуется к Т; это правильный тип, поэтому преобразование безопасно. Но при вызове гер снова делается попытка преобразования Object[] в Т[], которое остается неверным; в результате вы получите предупреждение во время компиляции и исключение во время выполнения. Не существует способа обойти тип базового массива, которым может быть только Object[]. У внутренней интерпретации array как Object[] вместо Т[] есть свои преимущества: например, вы с меньшей вероятностью забудете тип массива, что приведет к случайному появлению ошибок (впрочем, подавляющее большинство таких ошибок будет быстро выявлено на стадии выполнения).

В новом коде следует передавать метку типа. В обновленной версии Generic-Array выглядит так:

//: generics/Generic/\rrayWithTypeToken.java

import java.lang.reflect.*;

public class GenericArrayWithTypeToken<T> { private T[] array; @SuppressWarni ngs("unchecked")

public GenericArrayWithTypeToken(CIass<T> type, int sz) { array = (T[])Array.newInstance(type, sz);

}

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

}

public T get(int index) { return arrayCindex]; } // Expose the underlying representation: public T[] rep { return array; } public static void main(String[] args) {

GenericArrayWithTypeToken<Integer> gai =

new Generi cArrayWi thTypeToken<Integer>( Integer.class, 10);

// This now works:

Integer[] ia = gai.rep;

}

} ///

Метка типа Class<T> передается конструктору для восстановления информации после стирания, чтобы мы могли создать фактический тип нужного массива (предупреждения при преобразовании по-прежнему приходится подавлять @SuppressWarnings). Получив фактический тип, мы возвращаем его для получения желаемых результатов, как видно из main.

К сожалению, просмотрев исходный код стандартных библиотек Java SE5, вы увидите, что преобразования массивов Object в параметризованные типы происходят повсеместно. Например, вот как выглядит копирующий конструктор для создания ArrayList из Collection после некоторой правки и упрощения:

public ArrayList(Collection с) { size = c.sizeO;

elementData = (E[])new Object[size]; с.toArray(elementData):

}

В ArrayList.java подобные преобразования встречаются неоднократно. И конечно, при их компиляции выдается множество предупреждений.

Ограничения

Ограничения, уже упоминавшиеся ранее в этой главе, сужают круг параметров типов, используемых при параметризации. Хотя это позволяет предъявлять требования к типам, к которым применяется ваш параметризованный код, у ограничений имеется и другой, потенциально более важный эффект: возможность вызова методов, определенных в ограничивающих типах.

Поскольку стирание уничтожает информацию о типе, при отсутствии ограничений для параметров типов могут вызываться только методы Object. Но, если ограничить параметр подмножеством типов, вы сможете вызвать методы из этого подмножества. Для установления ограничений в Java используется ключевое слово extends. Важно понимать, что в контексте параметризации extends имеет совершенно иной смысл, нежели в обычной ситуации. Следующий пример демонстрирует основы установления ограничений:

//: generics/BasicBounds.java

interface HasColor { java. awt. Col or getColorO; }

class Colored<T extends HasColor> { T item:

Colored(T item) { this.item = item; }

T getltemO { return item; }

// Ограничение позволяет вызвать метод:

java. awt. Col or colore) { return item.getColorO; }

}

class Dimension { public int x, y. z; }

// Не работает -- сначала класс, потом интерфейсы: // class ColoredDimensiол<Т extends HasColor & Dimension> {

// Несколько ограничений-

class ColoredDimension<T extends Dimension & HasColor> { T item:

ColoredDimension(T item) { this.item = item, }

T getltemO { return item, }

java. awt. Col or colorO { return item getColorO; }

int getXO { return item.x; }

int getYO { return item.у, }

int getZO { return item z; }

}

interface Weight { int weightO; }

// Как и при наследовании, конкретный класс может быть только один, // а интерфейсов может быть несколько: class Solid<T extends Dimension & HasColor & Weight> { T item;

Solid(T item) { this.item = item. }

T get ItemО { return item; }

java.awt Color col orО { return item.getColor; }

int getXO { return item x; }

int getYO { return item у; }

int getZO { return item.z; }

int weightO { return item, weight О; }

}

class Bounded

extends Dimension implements HasColor. Weight {

public java.awt.Col or getColorO { return null; } public int weightO { return 0; }

}

public class BasicBounds {

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

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

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

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

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