Вот заметки, которые я сделал после изучения концепции Generics в java.

GENERICS:
1. Введение.
2. Универсальные классы.
3. Ограниченные типы.
4. Общие методы и подстановочные знаки.
5. Связь с другими -общий код.
6. Выводы.

Обобщения: Основная цель Обобщений
1. Обеспечение безопасности типов и
2. Решение проблемы приведения типов.
________________________________________________________________________________________________________________________________________________
1. Введение:
>
Преобразование типов - головная боль в коллекции, поэтому, чтобы преодолеть эту проблему, люди из SUN вводят концепцию Generics в версии 1.5.

Типовая безопасность:
Массивы являются типобезопасными, мы можем дать гарантию типа элементов, присутствующих внутри массива (кроме типов объектов)
Пример: если нам нужен массив строкового типа, мы делаем
Stirng[] str = new String[100];
Таким образом, мы не можем добавить какой-либо другой тип объекта, иначе получим ошибку времени компиляции.

Коллекции не являются типобезопасными, мы не можем гарантировать наличие объектов внутри коллекций. Здесь мы можем без проблем добавить любой тип во время компиляции, но во время выполнения произойдет сбой.
ArrayList list = new ArrayList();
list.add(“Vipul”);
список.добавить(1);

Приведение типов:
В случае массива во время извлечения от нас не требуется выполнять приведение типов, поскольку существует гарантия типа элемента, присутствующего внутри массива.
String s1 = str.get(1);
Строка s2 = str.get(0);

Но в случае коллекций во время извлечения от нас требуется приведение типов, потому что нет никакой гарантии для типа элемента, присутствующего внутри массива.

Список ArrayList = новый ArrayList();
list.add(“Vipul”);
list.add(1);
String s1 = (String)list.get(0);/ / приведение типов является обязательным.

Итак, After Generics становится: ArrayList‹String› list = new ArrayList‹String›();

Выводы:
1. Концепция полиморфизма применима только к базовому типу, но не к типу параметра.

Список‹Строка› список = новый ArrayList‹Строка›();
Коллекция‹String› list = new ArrayList‹String›();

ArrayList‹Object› list = new ArrayList‹String›(); X
Здесь база — ArrayList, а тип — Object и String.

2. Для типа мы можем указать любое имя класса или интерфейса, но не примитивный тип.
ArrayList‹int› list = new ArrayList‹int›(); Икс

______________________________________________________________________________________________________________________________________________

2. Общие классы.

class ArrayList‹T›{
add(T t);
T get(int index);
}
— на основе нашего времени выполнения T будет заменен предоставленным нами типом.

ArrayList‹String› list = new ArrayList‹String›();

class ArrayList‹String›{
add(String t);
T get(int index);
}

Вот пример универсального класса:

class Gen‹T› {
T obj;

Gen(T obj) {
this.obj = obj;
}

public void show() {
System.out.println("Тип объекта:" + obj.getClass().getName());
}

public T getObject() {
return obj;
}

}

Универсальные общедоступные классы {

public static void main(String[] args) {

Gen‹String› g1 = new Gen‹String›(“Vipul”);
g1.show();
System.out.println(g1.getObject());

Gen‹Integer› g2 = new Gen‹Integer›(1);
g2.show();
System.out.println(g2.getObject());

Gen‹Double› g3 = new Gen‹Double›(1.5);
g3.show();
System.out.println(g3.getObject());

}

}

______________________________________________________________________________________________________________________________________________
3. Ограниченные типы:
- Мы можем связать параметр типа для определенного диапазона, используя ключевые слова extends, такой тип называется ограниченным типом.
- Мы можем определить ограниченный тип только с помощью extends ключевое слово. (для типа реализации также используйте ключевое слово extends)
- В зависимости от требования мы можем взять любое количество параметров, разделенных запятой. (класс Gen‹key,value›{}, а также HashMap‹key,value›)

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

скажем: class Gen‹T›{
}
Gen‹Integer› g1 = new Gen‹Integer›();
Gen‹String› g1 = new Gen‹String›();

Итак, чтобы сделать его ограниченным типом:
class Gen‹T extends X›{
}
X: это может быть либо класс, либо интерфейс, если это класс, то в качестве параметра типа мы можем передать либо тип x, либо его дочерний тип.
X: если это интерфейс, мы можем передать либо тип X, либо его классы реализации.

Пример: 1
class Gen‹T extends Number›{
}
Gen‹Integer› g1 = new Gen‹Integer›();
Gen‹Float› g1 = new Gen ‹Float›();

Gen‹String› g1 = new Gen‹String›(); X это не будет работать, так как тип - это число. Ошибка времени компиляции
_________________________________________________________
Пример: 2
class Gen‹T extends Runnable›{
}
Gen‹Runnable› g1 = new Gen‹Runnable›();
Gen‹Thread› g1 = new Gen‹Thread›();

Gen‹Integer› g1 = new Gen‹Integer›(); X это не будет работать, так как тип Runnable. Ошибка времени компиляции

______________________________________________________________________________________________________________________________________________
4. Общий метод и подстановочные знаки:

1. m1(ArrayList‹String› l)
m1(ArrayList‹String› l){

}
— мы можем вызвать этот метод, передав arraylist только типа String, иначе мы получим ошибку времени компиляции.
m1(ArrayList‹String› l){
l.add(“abc”);
l.add(1); // CE:
}

2. m1(ArrayList‹?›l): (лучше всего подходит для операции только для чтения)
— мы можем вызвать этот метод, передав arraylist любого типа, но внутри метода мы не можем ничего добавить в список, кроме null , т. к. мы не знаем тип.
допускается null, т. к. это допустимое значение любого типа.
m1(ArrayList‹?› l){
l.add(“abc” ); X
l.add(1);
l.add(null);
}
ArrayList‹?› list = new ArrayList‹Integer›();
ArrayList‹?› list = new ArrayList‹String›();

3. m1(ArrayList‹? extends X› l)
— X может быть либо классом, либо интерфейсом.

Список Массивов‹? расширяет список чисел> = новый список_массивов‹целое›();
список_массивов‹?расширяет список чисел> = новый список_массивов‹строка›(); // СЕ:

4. m1(ArrayList‹? Super X› l)
- X может быть либо классом, либо интерфейсом.
- X является классом, тогда мы можем вызвать ArrayList либо типа x, либо его суперкласса.
>-X - это интерфейс, тогда мы можем вызвать этот метод по типу x или реализации суперкласса класса x. (Runnable -> Thread -> Object)
— Мы можем добавить только тип X и нулевой тип.

Список Массивов‹? Super String› l = new ArrayList‹Object›();

Мы можем определить ограниченный тип либо на уровне класса, либо на уровне метода.

Уровень класса.
class Test‹T›{

}
Уровень метода.
class Test{
public ‹T› void m1(T ob) {

}
}

Здесь T может быть:
1. ‹T расширяет Number›
2. ‹T расширяет Runnable›
3. ‹T расширяет Number & Runnable›
4. ‹T расширяет Number & Comparable›
5. ‹T расширяет число и поток›

______________________________________________________________________________________________________________________________________________

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

Основная цель обобщений — обеспечить безопасность типов и приведение типов, обе эти концепции применимы во время компиляции, следовательно, общая концепция также
применима во время компиляции, а не во время выполнения.
— во время компиляции в последний Общий синтаксис будет удален и, следовательно, для JVM Общий синтаксис будет недоступен.
Следовательно, все эти объявления равны.

Список ArrayList = новый ArrayList‹Integer›();
Список ArrayList = новый ArrayList‹String›();
Список ArrayList = новый ArrayList‹Double›();
Список ArrayList = новый ArrayList ();

ArrayList‹String› list = new ArrayList‹String›();
ArrayList‹String› list = new ArrayList();

// Здесь оба имеют одинаковую подпись, и мы получаем CE: обе подписи одинаковы.

class Test{
public void m1 (список ArrayList‹Integer›){}
public void m1 (список ArrayList‹String›){}
}

Источники: DurgaSoft, Stackoverflow, интернет….

Надеюсь, это поможет понять концепцию Generics в java.

Удачного кодирования!!