Так называемые дженерики: позволяют указывать параметры типа при определении классов и интерфейсов. Этот параметр типа будет определяться при объявлении переменных и создании объектов (то есть при передаче фактических параметров типа, которые также можно называть аргументами типа).
Общий класс или интерфейс
Код копирования синтаксиса «ромб» выглядит следующим образом:
//определение
общедоступный интерфейс List<E> расширяет Collection<E>
открытый класс HashMap<K,V> расширяет AbstractMap<K,V> реализует Map<K,V>, Cloneable, Serializable
//использовать
List<String> list = новый ArrayList();
//После Java 7 вы можете опустить параметр типа в угловых скобках позади него.
List<String> list = новый ArrayList<>();
Вывести подкласс из общего класса
Скопируйте код кода следующим образом:
//Метод 1
Приложение общедоступного класса расширяет GenericType<String>
//Метод 2
общедоступный класс App<T> расширяет GenericType<T>
//Метод 3
Приложение общедоступного класса расширяет GenericType
Псевдодженерики
Настоящего универсального класса не существует. Универсальные классы прозрачны для виртуальной машины Java. Другими словами, JVM обрабатывает универсальные классы так же, как обычные классы. Поэтому параметры типа не допускаются. в статических методах, статических блоках инициализации и статических переменных.
- Все следующие методы неверны. Код копирования кода следующий:
частные статические Т-данные;
статический {
Т ф;
}
публичная статическая пустота func(){
Т имя = 1;
}
Следующий пример позволяет проверить со стороны отсутствие универсального класса. Скопируйте код. Код выглядит следующим образом:
public static void main(String[] args){
List<String> a1 = новый ArrayList<>();
List<Integer> a2 = новый ArrayList<>();
System.out.println(a1.getClass() == a2.getClass());
System.out.println(a1.getClass());
System.out.println(a2.getClass());
}
Выходной код копирования выглядит следующим образом:
истинный
класс java.util.ArrayList
класс java.util.ArrayList
Введите подстановочный знак
Прежде всего, должно быть ясно, что если Foo является родительским классом Bar, но List<Foo> не является родительским классом List<Bar>. Для представления различных общих родительских классов Java использует знак «?». универсальные подстановочные знаки. То есть List<?> представляет родительский класс различных универсальных списков. С помощью подстановочных знаков такого типа универсальные символы списков не могут устанавливать (устанавливать) элементы, а могут только получать (получать) элементы. Поскольку программа не может определять типы в списке, она не может добавлять объекты. Но полученный объект должен быть типа Object.
Следующие методы компилируются с ошибками:
Скопируйте код кода следующим образом:
Список<?> список = новый ArrayList<>();
list.add(новый объект());
Некоторые идеи:
1. Объекты List<String> не могут использоваться как объекты List<Object>, то есть: класс List<String> не является подклассом класса List<Object>.
2. Массивы отличаются от обобщенных: если Foo является подтипом (подклассом или подинтерфейсом) Bar, то Foo[] по-прежнему является подтипом Bar[], но G<Foo> не является подтипом G<Bar>;
3. Чтобы представить родительский класс различных общих списков, нам нужно использовать подстановочные знаки типов. Подстановочный знак типа — это вопросительный знак (?). Передайте вопросительный знак в качестве аргумента типа в коллекцию List, записав: List<? > (имеется в виду неизвестный список элементов типа). Этот вопросительный знак (?) называется подстановочным знаком, и его тип элемента может соответствовать любому типу.
Верхний предел подстановочного знака
List<? расширяет SuperType> представляет родительский класс или сам все общие списки SuperType. Обобщенные методы с верхними пределами подстановочных знаков не могут иметь методы set, только методы get.
Установка верхнего предела подстановочных знаков может решить следующие проблемы: Dog является подклассом Animal, и существует метод getSize для получения количества входящих списков. Скопируйте код следующим образом.
абстрактный класс Animal {
публичный абстрактный недействительный запуск();
}
класс Dog расширяет Animal {
общественный недействительный запуск () {
System.out.println("Бег собаки");
}
}
приложение общедоступного класса {
public static void getSize(List<Animal> list) {
System.out.println(list.size());
}
public static void main(String[] args) {
List<Dog> list = новый ArrayList<>();
getSize(list); // Здесь ошибка компиляции
}
}
Причина ошибки программирования здесь заключается в том, что List<Animal> не является родительским классом List<Dog>. Первое решение — изменить формальный параметр List<Animal> в методе getSize на List<?>, но в этом случае принудительное преобразование типа требуется каждый раз при получении объекта, что является более хлопотным. Использование верхнего предела с подстановочными знаками очень хорошо решает эту проблему. Вы можете изменить List<Animal> на List<?extensions Animal>, и при компиляции не возникнет ошибок, и преобразование типов не потребуется.
Нижняя граница для подстановочных знаков
List<? super SubType> представляет нижний предел общего списка подтипов. Обобщенные методы с верхними пределами подстановочных знаков не могут иметь методы get, только методы set.
Общие методы
Если вы определяете классы и интерфейсы без использования параметров типа, но хотите самостоятельно определить параметры типа при определении методов, это также возможно. JDK1.5 также обеспечивает поддержку универсальных методов. В сигнатуре универсального метода содержится больше объявлений параметров типа, чем в сигнатуре обычного метода. Объявления параметров типа заключаются в угловые скобки. Несколько параметров типа разделяются запятыми (,). Все объявления параметров типа располагаются между методами. модификаторы и типы возвращаемых значений метода. Формат синтаксиса следующий:
Скопируйте код кода следующим образом:
Тип возвращаемого значения модификатора имя метода (список типов) {
//тело метода
}
Универсальные методы позволяют использовать параметры типа для выражения зависимостей типов между одним или несколькими параметрами метода или между возвращаемыми значениями метода и параметрами. Если такой зависимости типа нет, не следует использовать универсальные методы. Метод копирования коллекций использует общие методы:
Скопируйте код кода следующим образом:
public static <T> void copy(List<? super T> dest, List<? расширяет T> src){ ...}
Этот метод требует, чтобы тип src был подклассом типа dest или сам по себе.
Стереть и конвертировать
В строгом универсальном коде классы с универсальными объявлениями всегда должны иметь параметры типа. Однако для обеспечения совместимости со старым кодом Java также разрешено использовать классы с общими объявлениями без указания параметров типа. Если для этого универсального класса не указан параметр типа, параметр типа называется необработанным типом и по умолчанию соответствует первому типу верхнего предела, указанному при объявлении параметра.
Когда объект с общей информацией присваивается другой переменной без общей информации, вся информация о типе между угловыми скобками отбрасывается. Например, если тип List<String> преобразуется в List, проверка типа элементов коллекции List становится верхним пределом переменной типа (то есть Object). Эта ситуация называется стиранием.
Пример кода копирования выглядит следующим образом:
класс Apple<T расширяет число>
{
размер Т;
публичноеApple()
{
}
общественное Apple (размер T)
{
this.size = размер;
}
общественная пустота setSize (размер T)
{
this.size = размер;
}
общедоступный T getSize()
{
вернуть этот.размер;
}
}
публичный класс ErasureTest
{
public static void main(String[] args)
{
Apple<Integer> a = новое Apple<>(6 // ①);
// Метод getSize возвращает объект Integer
Целое число как = a.getSize();
// Назначаем объект a переменной Apple, теряя информацию о типе в угловых скобках
Яблоко б = а // ②
// b знает только, что тип размера — Number
Размер числа1 = b.getSize();
//Следующий код вызывает ошибку компиляции
Целочисленный размер2 = b.getSize() // ③;
}
}