
- •Глава 2 3
- •Глава 3 11
- •Глава 10 117
- •Глава 2 Автоупаковка и автораспаковка
- •Обзор оболочек типов и упаковки значений
- •Основы автоупаковки/распаковки
- •Автоупаковка и методы
- •Автоупаковка/распаковка в выражениях
- •Автоупаковка/распаковка логических и символьных значений
- •Помощь автоупаковки/распаковки в предупреждении ошибок
- •Предостережения
- •Глава 3 Настраиваемые типы
- •Что такое настраиваемые типы
- •Простой пример применения настраиваемых типов
- •Средства настройки типов работают только с объектами
- •Различия настраиваемых типов, основанных на разных аргументах типа
- •Как настраиваемые типы улучшают типовую безопасность
- •Настраиваемый класс с двумя параметрами типа
- •Общий вид объявления настраиваемого класса
- •Ограниченные типы
- •Применение метасимвольных аргументов
- •Ограниченные метасимвольные аргументы
- •Создание настраиваемого метода
- •Настраиваемые конструкторы
- •Настраиваемые интерфейсы
- •Типы raw и разработанный ранее код
- •Иерархии настраиваемых классов
- •Использование настраиваемого суперкласса
- •Настраиваемый подкласс
- •Сравнения типов настраиваемой иерархии во время выполнения программы
- •Переопределенные методы в настраиваемом классе
- •Настраиваемые типы и коллекции
- •Стирание
- •Методы-подставки
- •Ошибки неоднозначности
- •Некоторые ограничения применения настраиваемых типов
- •Нельзя создавать объекты, используя параметры типа
- •Ограничения для статических членов класса
- •Ограничения для настраиваемого массива
- •Ограничение настраиваемых исключений
- •Заключительные замечания
- •Глава 4 Вариант For-Each цикла for
- •Описание цикла for-each
- •Обработка многомерных массивов в цикле
- •Область применения цикла for в стиле for-each
- •Использование цикла for в стиле for-each для обработки коллекций
- •Создание объектов, реализующих интерфейс Iterable
- •Глава 5 Аргументы переменной длины
- •Средство формирования списка с переменным числом аргументов
- •Перегрузка методов с аргументом переменной длины
- •Аргументы переменной длины и неоднозначность
- •Глава 6 Перечислимые типы
- •Описание перечислимого типа
- •Методы values() и valueOf()
- •Перечислимый тип в Java — это класс
- •Перечислимые типы, наследующие тип enum
- •Глава 7 Метаданные
- •Описание средства "метаданные"
- •Задание правил сохранения
- •Получение аннотаций во время выполнения программы с помощью рефлексии
- •Листинг 7.3. Получение всех аннотаций для класса и метода
- •Интерфейс AnnotatedElement
- •Использование значений по умолчанию
- •Аннотации-маркеры
- •Одночленные аннотации
- •Встроенные аннотации
- •Несколько ограничений
- •Глава 8 Статический импорт
- •Описание статического импорта
- •Общий вид оператора статического импорта
- •Импорт статических членов классов, созданных Вами
- •Неоднозначность
- •Предупреждение
- •Глава 9 Форматированный ввод/вывод
- •Форматирование вывода с помощью класса Formatter
- •Конструкторы класса Formatter
- •Методы класса Formatter
- •Основы форматирования
- •Форматирование строк и символов
- •Форматирование чисел
- •Форматирование времени и даты
- •Спецификаторы %n и %%
- •Задание минимальной ширины поля
- •Задание точности представления
- •Применение флагов форматирования
- •Выравнивание вывода
- •Флаг запятая
- •Применение верхнего регистра
- •Использование порядкового номера аргумента
- •Применение метода printf() языка Java
- •Класс Scanner
- •Конструкторы класса Scanner
- •Описание форматирования входных данных
- •Несколько примеров применения класса Scanner
- •Установка разделителей
- •Другие свойства класса Scanner
- •Глава 10 Изменения в api
- •Возможность применения настраиваемых типов при работе с коллекциями
- •Обновление класса Collections
- •Почему настраиваемые коллекции
- •Модернизация других классов и интерфейсов для применения настраиваемых типов
- •Новые классы и интерфейсы, добавленные в пакет java.Lang
- •Класс ProcessBulider
- •Класс StringBuilder
- •Интерфейс Appendable
- •Интерфейс Iterable
- •Интерфейс Readable
- •Новые методы побитной обработки классов Integer и Long
- •Методы signum() u reverseBytes()
- •Поддержка 32-битных кодовых точек для символов Unicode
- •Новые подпакеты пакета java.Lang
- •Классы Formatter и Scanner
Настраиваемые конструкторы
Конструкторы также могут быть настраиваемыми, даже если их класс не является настраиваемым типом. Рассмотрим короткую программу, приведенную в листинге 3.9.
Листинг 3.9. Применение настраиваемого конструктора
class GenCons {
private double val;
<T extends Number> GenCons(T arg) {
val = arg.doubleValue();
}
void showval() {
System.out.println("val: " + val);
}
}
class GenConsDemo {
public static void main(String args[]) {
GenCons test = new GenCons(100);
GenCons test2 = new GenCons(123.5F);
test.showval();
test2.showval();
}
}
Далее приведен вывод программы из листинга 3.9:
val: 100.0
val: 123.5
Поскольку конструктор GenCons( ) задает параметр настраиваемого типа, который должен быть производным классом от класса Number, его можно вызвать c любым числовым типом, включая Integer, Float или Double.
Следовательно, хотя класс GenCons не является настраиваемым типом, его конструктор настраиваемый.
Настраиваемые интерфейсы
Кроме настраиваемых классов и методов Вы можете создавать настраиваемые интерфейсы (generic interface). Они задаются так же, как настраиваемые классы. В листинге 3.10 приведен пример настраиваемого интерфейса. В нем создается интерфейс, названный MinMax, объявляющий методы min() и mах(), которые должны возвращать минимальное и максимальное значения некоторого множества объектов.
Листинг 3.10. Пример настраиваемого интерфейса
// Интерфейс Min/Max.
interface MinMax<T extends Comparable<T>> {
T min();
T max();
}
// Теперь реализуем MinMax
class MyClass<T extends Comparable<T>> implements MinMax<T> {
T[] vals;
MyClass(T[] o) { vals = o; }
// Возвращает минимальное значение из vals.
public T min() {
T v = vals[0];
for(int i=1; i < vals.length; i++)
if(vals[i].compareTo(v) < 0) v = vals[i];
return v;
}
// Возвращает максимальное значение из vals. public T max() {
T v = vals[0];
for(int i=1; i < vals.length; i++)
if(vals[i].compareTo(v) > 0) v = vals[i];
return v;
}
}
class GenIFDemo {
public static void main(String args[]) {
Integer inums[] = {3, 6, 2, 8, 6 };
Character chs[] = {'b', 'r', 'p', 'w' };
MyClass<Integer> iob = new MyClass<Integer>(inums);
MyClass<Character> cob = new MyClass<Character>(chs);
System.out.println("Max value in inums: " + iob.max());
System.out.println("Min value in inums: " + iob.min());
System.out.println("Max value in chs: " + cob.max());
System.out.println("Min value in chs: " + cob.min());
}
}
Далее приведен вывод результатов работы программы из листинга 3.10:
Max value in inums: 8
Min value in inums: 2
Max value in chs: w
Min value in chs: b
Несмотря на то, что большая часть кода листинга 3.10 понятна, следует сделать несколько замечаний. Во-первых, обратите внимание на объявление интерфейса MinMax, приведенное в следующей строке:
interface MinMax<T extends Comparable<T>> {
Вообще настраиваемый интерфейс объявляется так же, как настраиваемый класс. В нашем случае параметр типа — T, и он должен расширять тип comparable. Обратите внимание на то, что тип comparable — тоже настраиваемый тип. Он принимает параметр типа, который задает тип сравниваемых объектов.
Далее класс MyClass реализует интерфейс MinMax. Рассмотрим объявление класса MyClass, приведенное в следующей строке:
class MyClass<T extends Comparable<T>> implements MinMax<T> {
Уделите особое внимание способу, которым параметр типа т объявляется в классе MyClass и затем передается в интерфейс MinMax. Поскольку интерфейсу MinMax требуется тип, расширяющий тип comparable, в классе, реализующем интерфейс (в нашем случае MyClass), должна быть задана та же самая граница. Более того, как только эта граница установлена, нет необходимости задавать ее снова в той части объявления класса, которая начинается с ключевого слова implements, На самом деле подобное действие было бы ошибкой. Например, приведенная далее часть кода некорректна и не будет компилироваться.
// Это неправильно!
class MyClass<T extends Comparable<T>>
implements MinMax<T extends Comparable<T>> {
Уже заданный параметр типа просто передается в интерфейс без дальнейшей модификации.
Вообще, если класс реализует настраиваемый интерфейс, этот класс также должен быть настраиваемым, по крайней мере, до той степени, которая обеспечивает получение параметра типа и передачу его в интерфейс. Например, приведенная далее строка кода, в которой делается попытка объявить класс MyClass, ошибочна:
class MyClass implements MinMax<T> { //Ошибка!
Поскольку в классе MyClass не объявлен параметр типа, не существует способа передачи его в интерфейс MinMax. В данном случае идентификатор T просто неизвестен, и компилятор сообщит об этой ошибке. Конечно, если класс реализует конкретную версию настраиваемого интерфейса, такую как приведенная в следующей строке:
class MyClass implements MinMax<Integer> { // OK
реализующему классу нет необходимости быть настраиваемым.
Применение настраиваемого интерфейса обладает двумя преимуществами. Во-первых, интерфейс можно реализовать для данных разных типов. Во-вторых, у вас появляется возможность наложить ограничения (т. е. установить границы) на типы данных, для которых может быть реализован интерфейс. В случае интерфейса MinMax, например, только типы, реализующие интерфейс comparable, могут передаваться для замены параметра T.
Далее приведена обобщенная синтаксическая конструкция для описания настраиваемого интерфейса:
interface interface-name<type-param-list> {//...
В данной записи type-param-list — это разделенный запятыми список параметров типа. Когда настраиваемый интерфейс реализуется, Вы должны заменить его списком аргументов типа, как показано в следующей строке:
class class-name<type-param-list>
implements interface-name<type-param-list> {//...