- •1. Java. Основные синтаксические структуры языка Java. Типы данных Java. Массивы.
- •2. Концепции ооп. Классы и объекты. Ключевые свойства объектов. Инкапсуляция. Время жизни объектов. Конструкторы.
- •3. Наследование и полиморфизм. Спецификаторы доступа (private, protected, public). Иерархия классов. Перечисления. Интерфейсы и абстрактные классы.
- •4. Статические поля и методы. Порождающие методы. Блоки инициализации. Статические внутренние классы.
- •5. Внутренние, локальные и анонимные классы. Пакеты. Компиляция классов. Jar-файлы.
- •События. Виды событий. Иерархия классов событий. Команда и источник. Адаптеры. (читаем картинки слева направо, потом на новую строку)
- •Принципы создания пользовательского интерфейса. Контейнеры, панели. Основные компоненты библиотеки Swing.
- •26. Потоки выполнения. Синхронизация и сигнализирование с помощью Lock.
- •27. Дополнительные возможности синхронизации. Справедливая блокировка. Барьер, затвор, семафор.
- •Барьеры
- •28. Расширенные методы синхронизации. Блокировка чтения и записи, Exchanger. Многопоточные приложения и Swing.
- •29. Настраиваемые типы данных. Универсальные классы. Ограничения на тип.
- •30. Настраиваемые типы данных. Универсальные методы. Ограничения в использовании настраиваемых типов.
29. Настраиваемые типы данных. Универсальные классы. Ограничения на тип.
По существу настраиваемые типы — это параметризованные типы (parameterized type). Они очень важны, так как позволяют Вам создавать классы,интерфейсы и методы, в которых тип обрабатываемых данных задается как параметр. С помощью настраиваемых типов можно, например, создать один класс, автоматически оперирующий разными типами данных. Класс, интерфейс или метод, работающие с параметризованными типами, называются настраиваемыми (generic). Важно помнить, что в языке Java, всегда существовала возможность создавать обобщенные или универсальные (generalized) классы, интерфейсы и методы с помощью ссылки на тип Object. Поскольку тип Object — это суперкласс для всех остальных классов, ссылка на него, по сути, позволяет ссылаться на объект любого типа. Таким образом, в исходных текстах программ, существовавших до появления настраиваемых типов, обобщенные классы, интерфейсы и методы использовали ссылки на тип Object для работы с различными типами данных. Проблема заключалась в том, что подобная обработка не обеспечивала типовой безопасности. Средства настройки типов обеспечили недостающую типовую безопасность. Они также модернизировали процесс, потому что отпала необходимость в явном приведении типов (Type cast) при переходе от типа Object к конкретному обрабатываемому типу. Благодаря введению настраиваемых типов все приведения выполняются автоматически и скрыто. Таким образом, применение настраиваемых типов расширяет возможности повторного использования кода и делает этот процесс легким и безопасным.
Создадим универсальное описание типа, изменяя код "public class Box" на "public class Box<T>"; здесь вводим одну переменную типа, названную T, которая может использоваться где-нибудь в классе. Эта методика может быть применена также к интерфейсам. Нет ничего особенно сложного в этой концепции. Фактически, это весьма подобно тому, что Вы уже знаете о переменных вообще. Только думайте о T как о специальном виде переменной, "значение" которой будет любым типом, в котором Вы нуждаетесь; это может быть любым типом класса, любым типом интерфейса, или даже другой переменной типа. Она только не может быть ни одинм из примитивных типов данных. В этом контексте мы также говорим, что T - формальный параметр типа класса Box.
Поскольку Вы можете видеть, что мы заменили все вхождения Object с T. Чтобы сослаться на этот универсальный класс изнутри Вашего собственного кода, Вы должны выполнить универсальный вызов типа, который заменяет T некоторым конкретным значением, например, Integer:
Box<Integer> integerBox;
Вы можете думать об универсальном вызове типа как о похожем на обычный вызов метода, но вместо того, чтобы передать аргумент методу, Вы передаете аргумент типа — Integer в этом случае - к классу Box непосредственно. Как любая другая переменная декларация, этот код фактически не создает новый объект Box. Он просто объявляет, что integerBox будет хранить ссылку на "BoxInteger", который является, как Box<Integer> при чтении.
Вызов универсального типа является общеизвестным как параметризуемый тип.
Чтобы создать экземпляр этого класса, используйте ключевое слово new, как обычно, но поместите <Integer> между именем класса и круглой скобкой:
integerBox = new Box<Integer>();
Или, Вы можете поместить весь оператор в одной строке, например:
Box<Integer> integerBox = new Box<Integer>();
Ограничения типа.
Могут быть времена, когда Вы будете хотеть ограничить виды типов, которым позволяют быть переданными параметру типа. Например, метод, который оперирует с числами, мог бы только принять экземпляры класса Number или его подклассов. Это - то, для чего нужны ограниченные параметры типа.
Чтобы объявить ограниченный параметр типа, перечислите имя параметра типа, сопровождаемое ключевым словом extends, сопровождаемым его верхней границей, которая в этом примере является Number. Обратите внимание, что, в этом контексте,extends используется в общем смысле означает, что любой "extends" (как в классах) или "implements" (как в интерфейсах).
/**
* This version introduces a bounded type parameter.
*/
public class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
public <U extends Number> void inspect(U u){
System.out.println("T: " + t.getClass().getName());
System.out.println("U: " + u.getClass().getName());
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
integerBox.add(new Integer(10));
integerBox.inspect("some text"); // error: this is still String!
}
}
Изменяя наш универсальный метод, чтобы включить этот ограниченный параметр типа, компиляция будет терпеть неудачу, так как наш вызов inspect все еще включает String:
Box.java:21: <U>inspect(U) in Box<java.lang.Integer> cannot
be applied to (java.lang.String)
integerBox.inspect("10");
^
1 error
Чтобы определить дополнительные интерфейсы, которые должны быть реализованы, используют & символ, как в:
<U extends Number & MyInterface>
