Назад Зміст Вперед

5.1. Оголошення Generic-класів. Призначення Generics

Узагальнення (Generic)

Generic - це параметризовані типи, за допомогою яких можна оголошувати класи, методи та інтерфейси, де тип даних заданий у вигляді параметру. Узагальнене програмування - це такий підхід до опису даних і алгоритмів, який дозволяє їх використовувати з різними типами даних без зміни їх опису.

Три переваги Generic:

1. Безпека (можна провести тільки один тип об'єктів, це не дозволяє зберігати інші об'єкти).
2. Не потрібно робити приведення типів.
3. Перевірка часу компіляції: помилка компіляції «краще» помилки часу виконання.

Приклад з Generic.
class Gen<T> { T ob; // оголошення об'єкта типу T 

// Передати конструктору посилання на об'єкт типу T 
Gen(T o) { 
ob = o; 

// Повернути ob 
T getob() { 
return ob; 

// Показати тип T 
void showType() { 
System.out.println("Тип T: " + ob.getClass().getName()); 

// Код для кнопки 
Gen<Integer> iOb; // Створюємо Gen-ссилку для Integer
Gen<Integer> iOb = new Gen<Integer>(77); // Створюємо об'єкт 
iOb.showType(); // Показати тип даних, який використовує iOb
int value = iOb.getob(); // Отримати значення iOb
System.out.println("Значення " + value); 

// Створення об'єкту Gen для String 
Gen<String> strOb = new Gen<String>("Загальний текст"); 
strOb.showType(); // Показати тип даних, який використовує strOb 
String str = strOb.getob(); // Отримати значення strOb
System.out.println("Значення: " + str);

Output:
Типом T є java.lang.Integer 
Значення: 77 
Типом T є java.lang.String 
Значення: Узагальнений текст

В попередньому прикладі оголошено клас в такій формі: 
class Gen<T> { }
У кутових дужках використовується T - ім'я параметра типу. Це ім'я використовується як заповнювач, куди буде підставлена ім'я реального типу, переданого класу Gen при створенні реальних типів. Тобто параметр типу T застосовується в класі щоразу, коли потрібно параметр типу. Кутові дужки вказують, що параметр може бути узагальнений. Сам клас при цьому називається узагальненим класом або параметризованим типом. Далі тип T використовується для декларування об'єкта на ім'я ob: 
T ob; // оголошено об'єкт типу T
Замість T буде підставлено реальний тип, який буде вказано при створенні об'єкта класу Gen. Об'єкт ob буде об'єктом типу, переданого в параметрі типу T. Якщо в параметрі T передати тип String, то екземпляр ob матиме тип String.

Розглянемо конструктор Gen ().
Get(T o) {
ob = o;
}

Параметр o має тип T. Це означає, що реальний тип параметра o визначається типом, переданим параметром типу T при створенні об'єкта класу Gen.

Параметр типу T також може бути використаний для вказівки типу значення, що повертається методу: 
T getob() {
return ob;
}

Як використовувати узагальнений клас.
Можна створити версію класу Gen для цілих чисел: 
Gen<Integer> iOb; 
У кутових дужках вказано тип Integer, тобто це аргумент типу, який передається в параметрі типу T класу Gen. Фактично ми створюємо версію класу Gen, в якій всі посилання на тип T стають посиланнями на тип Integer.

Коли ми присвоюємо посилання на екземпляр, то кутові дужки також потрібно вказувати. 
iOb = new Gen<Integer>(77);

Повна версія запису може бути такою:
iOb = new Gen<Integer>(new Integer(88)); 

Але такий запис надлишковий, так як можна використовувати автоматичну упаковку значення 77 в потрібний формат.

Аналогічно, можна було б використовувати варіант без автоупаковки для отримання значення: int value = iOb.getob().intValue(); // зайвий код 

Узагальнення працюють тільки з об'єктами. Тому не можна використовувати в якості параметра елементарні типи на кшталт int або char

Gen<int> intOb = new Gen<int>(44); // так не можна!

Хоча об'єкти iOb і strOb мають тип Gen <T> , вони є посиланнями на різні типи і їх порівнювати не можна. 

iOB = strOb; // не можна!

Використання узагальнень автоматично гарантує безпеку типів у всіх операціях, де вони задіяні. Це дуже потужний механізм, який широко використовується в Java.

Узагальнений клас з двома параметрами

Можна вказати два і більше параметрів типу через кому. 
class TwoGen<T, V> { 
T ob1; V ob2; // Передати конструктору ссилки на об'єкти двох типів 
TwoGen(T o1, V o2) {
ob1 = o1; 
ob2 = o2; 
void showTypes() { 
System.out.println("Тип T: " + ob1.getClass().getName());
System.out.println("Тип V: " + ob2.getClass().getName());
T getob1() { 
return ob1; 
V getob2() {
return ob2; 
// Використання створеного класу
TwoGen<Integer, String> twogenObj = new TwoGen<Integer, String>(77, "Загальний текст"); 
// дізнатися типи
twogenObj.showTypes(); 
// дізнатися значення
int value = twogenObj.getob1(); 
System.out.println("Значення: " + value); 
String str = twogenObj.getob2(); 
System.out.println("Значення: " + str); 
}

Синтаксис Generic:ClassOrInterface <Type>

Приклад використання Generic в Java:
ArrayList<String>

Приклад коду:

import java.util.*;
class TestGenerics1{
public static void main(String args[]){
ArrayList<String> list=new ArrayList<String>();
list.add("rahul");
list.add("jai");
//list.add(32);
//compile time error

String s=list.get(1);//не потрібно приводити типи
System.out.println("element is: "+s);
Iterator<String> itr=list.iterator();
while(itr.hasNext()){
System.out.println(itr.next());
}
}
}
Output:
element is: jai
rahul
jai

Приклад використання Generic для Map:

import java.util.*; 
 class TestGenerics2{ 
 public static void main(String args[]){ 
 Map<Integer,String> map=new HashMap<Integer,String>(); 
 map.put(1,"vijay"); 
 map.put(4,"umesh"); 
 map.put(2,"ankit"); 
 //Now use Map.Entry for Set and Iterator 
 Set<Map.Entry<Integer,String>> set=map.entrySet(); 
 Iterator<Map.Entry<Integer,String>> itr=set.iterator(); 
 while(itr.hasNext()){ 
 Map.Entry e=itr.next();
//no need to typecast 
System.out.println(e.getKey()+" "+e.getValue()); 
}
}
}

Output:
1 vijay
2 ankit
4 umesh

Generic class

Тут використано параметр типу Т, щоб створити загальний клас конкретного типу.

Приклад 1 створення generic class:

class MyGen<T>{
T obj; 

void add(T obj){
this.obj=obj;

T get(){
return obj;
}
Тип T може бути будь-яким (наприклад, String, Integer, Employee і т.д.).

Приклад 2.

class TestGenerics3{ 
 public static void main(String args[]){ 
 MyGen<Integer> m=new MyGen<Integer>(); 
 m.add(2); 
//m.add("vivek");
//Compile time error 
 System.out.println(m.get()); 
 }
}
Output:2

Найпоширеніші типи параметрів (Parameters):

T - Type 
E - Element
K - Key
N - Number
V - Value
.