java tutorial - Руководство Java Generics - учебник java - java programming - учиться java - java basics - java for beginners



1- Почему Java Generics?

  • Generics это понятие, введенное в Java, начиная с версии 5. Перед тем, как ознакомить вас с понятием Generics, посмотрим на код Java перед версией 5.
  • В данном примере, ArrayList это списко, вы можете добавить., удалить, изменить в списке, и иметь доступ к элементам в списке.

BeforeJ5Example.java

package org.wikitechy.tutorial.generics;
 
import java.util.ArrayList;
 
public class BeforeJ5Example {
 
    public static void main(String[] args) {
 
        // Создать объект ArrayList (Список).
        // Чтобы содержать имена пользователей.
        ArrayList userNames = new ArrayList();
 
        // Добавить String в список.
        userNames.add("tom");
        userNames.add("jerry");
 
        // Вы случайно добавляете элемент не String вида в список.
        // (Это вполне позволено).
        userNames.add(new Integer(100));
 
        // И получить первый элемент
        // Он является Object (Но вы знаете, что он является String)
        // ==> tom
        Object obj1 = userNames.get(0);
 
        // Сделать cast в String.
        String userName1 = (String) obj1;
 
        System.out.println("userName1 = " + userName1);
 
        // Получить элемент 2.
        // (Вы знаете, что он является String)
        // ==> jerry
        String userName2 = (String) userNames.get(1);
 
        System.out.println("userName2 = " + userName2);
 
        // Получить 3-ий элемент и сделать cast чтобы он стал String.
        // (На самом деле он является Integer).
        // (Ошибка cast происходит здесь).
        String userName3 = (String) userNames.get(2);
 
        System.out.println("userName3 = " + userName3);
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

Ситуация в Java перед версией 5:

  • Вам нужно создать объект ArrayList с целью хранения только элементов вида String, при этом добавить в этот список элемент не вида String где-нибудь в программе (Это вполне возможно), когда вы получаете эти элементы и приводите к виду String, выбрасывается исключение.TODO (Image)
  • Java 5 вводит понятие Generics. С помощью Generics, вы можете создать объект ArrayList который позволяет содержать только объекты вида String, и не позволяет иметь другие виды объектов.

J5Example.java

package org.wikitechy.tutorial.generics;
 
import java.util.ArrayList;
 
public class J5Example {
 
    public static void main(String[] args) {
 
        // Создать ArrayList (Список)
        // Этот список только позволяет содержать элементы вида String.
        ArrayList<String> userNames = new ArrayList<String>();
 
        // Добавить String в список.
        userNames.add("tom");
        userNames.add("jerry");
 
        // Вы не можете добавить элементы не String вида в список.
        // (Ошибка при компиляции).
        userNames.add(new Integer(100)); // Compile Error!
 
        // Вам не нужно делать cast элемента.
        String userName1 = userNames.get(0);
 
        System.out.println("userName1 = " + userName1);
 
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда
 Пример J5
java - джава - учиться java - учебник java -
Пример J5
- примеры java - java-программы
  • Когда вы создаете объект ArrayList <String>, он содержить только элементы вида String, компилятор Java не позволяет этому объекту содержать элементы отличающиеся от String.

2- ВидGeneric для Class & Interface

2.1- Generics Class

  • ример ниже определяет class generics. KeyValueэто class generics который содержит пару ключей/значения (key/value).

KeyValue.java

package org.wikitechy.tutorial.generics.ci;
 
public class KeyValue<K, V> {
 
   private K key;
   private V value;
 
   public KeyValue(K key, V value) {
       this.key = key;
       this.value = value;
   }
 
   public K getKey() {
       return key;
   }
 
   public void setKey(K key) {
       this.key = key;
   }
 
   public V getValue() {
       return value;
   }
 
   public void setValue(V value) {
       this.value = value;
   }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда
  • K, V в class KeyValue называется параметорм generics, который является определенной ссылкой. При использовании этого class-а вам нужно определить точный параметр.
  • Смотрите пример использования class KeyValue.

KeyValueDemo.java

package org.wikitechy.tutorial.generics.ci;
 
public class KeyValueDemo {
 
    public static void main(String[] args) {
 
        // Создать объект KeyValue
        // Integer: Номер телефона (K = Integer)
        // String: Имя пользователя. (V = String).
        KeyValue<Integer, String> entry = new KeyValue<Integer, String>(12000111, "Tom");
 
        // Java понимает вид возврата как Integer (K = Integer).
        Integer phone = entry.getKey();
 
        // Java понимает вид возврата как String (V = String).
        String name = entry.getValue();
 
        System.out.println("Phone = " + phone + " / name = " + name);
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

Запуск примера:

 значение ключа демо
java - джава - учиться java - учебник java -
значение ключа демо
- примеры java - java-программы

2.2- Наследование класса Generics

  • Сlass расширенный из class generics, может определить вид параметра generics, сохранить параметры generics или добавить параметры generics.

Пример 1:

PhoneNameEntry.java

package org.wikitechy.tutorial.generics.ci;
 
// Этот класс расширенный (extends) из класса KeyValue<K,V>.
// И ясно определяет K,V:
// K = Integer  (Номер телефона).
// V = String   (Имя пользователя).
public class PhoneNameEntry extends KeyValue<Integer, String> {
 
    public PhoneNameEntry(Integer key, String value) {
        super(key, value);
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

Пример использования PhoneNameEntry:

package org.wikitechy.tutorial.generics.ci;
 
public class PhoneNameEntryDemo {
 
    public static void main(String[] args) {
 
        PhoneNameEntry entry = new PhoneNameEntry(12000111, "Tom");
 
        // Java понимает вид возврата как Integer.
        Integer phone = entry.getKey();
 
        // Java понимает вид возврата как String.
        String name = entry.getValue();
 
        System.out.println("Phone = " + phone + " / name = " + name);
 
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

Пример 2:

StringAndValueEntry.java

package org.wikitechy.tutorial.generics.ci;
 
// Этот класс расширен (extends) из класса KeyValue<K,V>.
// Ясно определить вид параметра <K> как String.
// Сохранить вид параметра Generic <V>.
public class StringAndValueEntry<V> extends KeyValue<String, V> {
 
    public StringAndValueEntry(String key, V value) {
        super(key, value);
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

Пример использования StringAndValueEntry class:

package org.wikitechy.tutorial.generics.ci;
 
public class StringAndValueEntryDemo {
 
    public static void main(String[] args) {
 
        // (Код сотрудника, Имя сотрудника).
        // V = String (Имя сотрудника)
        StringAndValueEntry<String> entry = new StringAndValueEntry<String>("E001", "Tom");
 
        String empNumber = entry.getKey();
 
        String empName = entry.getValue();
 
        System.out.println("Emp Number = " + empNumber);
        System.out.println("Emp Name = " + empName);
 
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

Пример 3:

package org.wikitechy.tutorial.generics.ci;
 
// Этот класс расширен (extends) из класса KeyValue<K,V>
// Он имеет еще один параметр Generics <I>.
public class KeyValueInfo<K, V, I> extends KeyValue<K, V> {
 
    private I info;
 
    public KeyValueInfo(K key, V value) {
        super(key, value);
    }
 
    public KeyValueInfo(K key, V value, I info) {
        super(key, value);
        this.info = info;
    }
 
    public I getInfo() {
        return info;
    }
 
    public void setInfo(I info) {
        this.info = info;
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

2.3- Generics Interface

  • Интерфейс с параметром Generics:

GenericInterface.java

package org.wikitechy.tutorial.generics.ci;
 
public interface GenericInterface<G> {
 
  
  public G doSomething();
  
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда
  • Пример class-а, применяющего интерфейс:

GenericInterfaceImpl.java

package org.wikitechy.tutorial.generics.ci;
 
public class GenericInterfaceImpl<G> implements GenericInterface<G>{
 
   private G something;
    
   @Override
   public G doSomething() {
       return something;
   }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда
  • Пример class-а, применяющего интерфейс:

GenericInterfaceImpl.java

package org.wikitechy.tutorial.generics.ci;
 
public class GenericInterfaceImpl<G> implements GenericInterface<G>{
 
   private G something;
    
   @Override
   public G doSomething() {
       return something;
   }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

2.4- Java не поддерживает Generics Throwable

  • Вы не можете создать class generic который является наследником Throwable, java не поддерживет создание такого class-а
 универсальный класс исключения
java - джава - учиться java - учебник java -
универсальный класс исключения
- примеры java - java-программы
  • Сообщение ошибки компилятора:
  • Java не поддерживает создание class-а Throwable generic, так как это не приносит никакую пользу. Причиной является информация Generic только используется компилятором для управления кодом программиста. В процессе запуска Java информация Generic не существует, объект Mistake или Mistake являются объектом Mistake.
} catch( Mistake<Account> ea) {
    // Если происходит исключение Mistake, данный блок будет выполнен.
    ...
} catch( Mistake<User> eu) {
     // Данный блок никогда не выполняется
    ...
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

3- Методы generics

  • Метод в class или интерфейсе, который может стать generic (generify).

MyUtils.java

package org.wikitechy.tutorial.generics.m;
 
import java.util.ArrayList;
 
import org.wikitechy.tutorial.generics.ci.KeyValue;
 
public class MyUtils {
 
    // <K,V> : Говорит этот метод имеет 2 вида параметра K,V
    // Метод возвращает объект вида K.
    public static <K, V> K getKey(KeyValue<K, V> entry) {
        K key = entry.getKey();
        return key;
    }
 
    // <K,V> : Говорит этот метод имеет 2 вида параметра K,V
    // Метод возвращает объект вида V.
    public static <K, V> V getValue(KeyValue<K, V> entry) {
        V value = entry.getValue();
        return value;
    }
 
    // ArrayList<E>: Список содержит элемент вида E.
    // Метод возвращает объект вида E.
    public static <E> E getFirstElement(ArrayList<E> list) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        E first = list.get(0);
        return first;
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда
  • Например, используя метод generics:

MyUtilsDemo.java

package org.wikitechy.tutorial.generics.m;
 
import java.util.ArrayList;
 
import org.wikitechy.tutorial.generics.ci.KeyValue;
 
public class MyUtilsDemo {
 
    public static void main(String[] args) {
 
        // K = Integer: Phone
        // V = String: Name
        KeyValue<Integer, String> entry1 = new KeyValue<Integer, String>(12000111, "Tom");
        KeyValue<Integer, String> entry2 = new KeyValue<Integer, String>(12000112, "Jerry");
 
        // (K = Integer).
        Integer phone = MyUtils.getKey(entry1);
        System.out.println("Phone = " + phone);
 
        // Список содержит элементы вида KeyValue<Integer,String>.
        ArrayList<KeyValue<Integer, String>> list = new ArrayList<KeyValue<Integer, String>>();
 
        // Добавить элемент в список.
        list.add(entry1);
        list.add(entry2);
 
        KeyValue<Integer, String> firstEntry = MyUtils.getFirstElement(list);
 
        System.out.println("Value = " + firstEntry.getValue());
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

MyUtilsDemo.java

package org.wikitechy.tutorial.generics.m;
 
import java.util.ArrayList;
 
import org.wikitechy.tutorial.generics.ci.KeyValue;
 
public class MyUtilsDemo {
 
    public static void main(String[] args) {
 
        // K = Integer: Phone
        // V = String: Name
        KeyValue<Integer, String> entry1 = new KeyValue<Integer, String>(12000111, "Tom");
        KeyValue<Integer, String> entry2 = new KeyValue<Integer, String>(12000112, "Jerry");
 
        // (K = Integer).
        Integer phone = MyUtils.getKey(entry1);
        System.out.println("Phone = " + phone);
 
        // Список содержит элементы вида KeyValue<Integer,String>.
        ArrayList<KeyValue<Integer, String>> list = new ArrayList<KeyValue<Integer, String>>();
 
        // Добавить элемент в список.
        list.add(entry1);
        list.add(entry2);
 
        KeyValue<Integer, String> firstEntry = MyUtils.getFirstElement(list);
 
        System.out.println("Value = " + firstEntry.getValue());
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

4- Инициализация объекта Generic

  • Иногда вы хотите инициировать объект Generic:
// Создать объект Generic.
T t = new T(); // Error
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда
Инициализация объекта generic, как выше не позволено, так как <T> не существует в момент запуска Java. Он имеет значение только для компилятора, управляющего кодом программиста. Все виды   <T> похожи друг на друга и понимаются как Object в момент запуска Java. 

Для инициализации объекта generic <T> вам нужно предоставить Java объект Class<T>, Java создаст объект <T> в момент запуска используя  Java Reflection.
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

Bar.java

package org.wikitechy.tutorial.generics.o;
 
import java.util.Date;
 
public class Bar {
 
    // Этот класс должен иметь Constructor (конструктор) по умолчанию .
    public Bar() {
 
    }
 
    public void currentDate() {
        System.out.println("Now is: " + new Date());
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

MyGeneric.java

package org.wikitechy.tutorial.generics.o;
 
public class MyGeneric<T> {
 
   private T tobject;
 
   public MyGeneric(Class<T> tclass)
           throws InstantiationException, IllegalAccessException {
        
       this.tobject = (T) tclass.newInstance();
        
   }
 
   public T getTObject() {
       return this.tobject;
   }
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

MyGenericDemo.java

package org.wikitechy.tutorial.generics.o;
 
public class MyGenericDemo {
 
   public static void main(String[] args) throws Exception {
 
       MyGeneric<Bar> mg = new MyGeneric<Bar>(Bar.class);
 
       Bar bar = mg.getTObject();
 
       bar.currentDate();
   }
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

5- Массив Generic

  • Вы можете объявить массив generic, но вы не можете создать массив generic.
// Вы можете объявить массив generic.
T[] myarray;
 
// Но не можете инициализировать массив generic.
// (Это не разрешено).
T[] myarray = new T[5];  // Error!
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

Пример:

GenericArray.java

package org.wikitechy.tutorial.generics.a;
 
public class GenericArray<T> {
 
    private T[] array;
 
    // Contructor.
    public GenericArray(T[] array) {
        this.array = array;
    }
 
    public T[] getArray() {
        return array;
    }
 
    // Возвращает последний элемент массива.
    public T getLastElement() {
        if (this.array == null || this.array.length == 0) {
            return null;
        }
        return this.array[this.array.length - 1];
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

GenericArrayDemo.java

package org.wikitechy.tutorial.generics.a;
 
public class GenericArrayDemo {
 
    public static void main(String[] args) {
 
        // Массив String.
        String[] names = new String[] { "Tom", "Jerry" };
 
        GenericArray<String> gArray = new GenericArray<String>(names);
 
        String last = gArray.getLastElement();
         
        System.out.println("Last Element = " + last);
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда
  • Возвращаясь к вопросу, почему Java не поддерживает инициализацию массива Generic:
// Почему Java не поддерживает инициализировать массив Generic?
T[] genericArray = new T[10]; // Error!
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда
  • Это потому что вид generic не существует в момент запуска, List или List это List. Generic только работает с компиляторами для управления кодом программиста. Это означает, что компилятору Java нужно знать точно, что такое для компиляции (compile) new T[10];. Если не знает точно, то по умолчанию считает T как Object. Тогда:
// Допустим Java позволяет инициализировать массив Generic:
T[]  tarray = new T[10];
 
// Во время компиляции (Compile-time)
// компилятор будет считать <T> как Object.
// Команда выше индентична:
T[] tarray  = new Object[10];
 
// Если во время запуска приложения, вы определяете <T> как String.
// Значит:
String[] tarray = new Object[10];
 
// Пункт выше не разрешен. Причина:
// Type mismatch: cannot convert from Object[] to String[]
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда
  • Если вы хотите инициализировать массив Generic вам нужно передать Java объект Class, помогая Java создать массив generic в момент запуска используя Java Reflection. Смотрите изображенный пример:

GArray.java

package org.wikitechy.tutorial.generics.a;
 
import java.lang.reflect.Array;
 
public class GArray<T> {
 
  private Class<T> tclass;
 
  private T[] myArray;
 
  public GArray(Class<T> tclass) {
      this.tclass = tclass;
 
      final int size = 10;
      myArray = (T[]) Array.newInstance(tclass, size);
  }
 
  public T[] getMyArray() {
      return this.myArray;
  }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

GArrayDemo.java

package org.wikitechy.tutorial.generics.a;
 
public class GArrayDemo {
 
   public static void main(String[] args) {
 
       GArray<Integer> garray = new GArray<Integer>(Integer.class);
 
       Integer[] myArray = garray.getMyArray();
 
       myArray[0] = 1;
       myArray[2] = 0;
   }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

6- Generics с Wildcards

  • В коде Generic, знак вопроса (?), называется wildcard, который представляет неопределенный вид. Вид параметра wildcard (wildcard parameterized type) это случай вида Generic, там где минимум один параметр является wildcard.
  • Пример вида параметра wildcard (wildcard parameterized) :
    • Collection
    • List extends Number>
    • Comparator super String>
    • PairString.
  • Wildcard могут использованы в разныъ ситуациях: как вид параметра, поле (field), или локальная переменная; иногда как возвратный вид (Будет объяснено в практических примерах). Wildcard никогда не использованы как аргумент для вызова метода Generic, создания объекта class generic, или супертип (supertype).
  • Wildcard находящиеся в разных позициях имеют разные значения:
    • Collection denotes all instantiations of the Collection interface regardless of the type argument.
    • List extends Number denotes all list types where the element type is a subtype of Number.
    • Comparator super String denotes all instantiations of the Comparator interface for type argument types that are supertypes of String.
  • Wildcard вида параметра не является конкретным видом, который может появиться в операторе new. Он только является подсказкой применяющегося правила, с помощью generics java, что какой вид имеет действие в определенном случае, где wildcard был использован.
Collection<?> coll = new ArrayList<String>();
 
// Набор содержит только вид Number или подвид Number
List<? extends Number> list = new ArrayList<Long>();
 
// Объект с подстановочным видом параметра.
// (A wildcard parameterized type)
Pair<String,?> pair = new Pair<String,Integer>();
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда
  • Некоторые недействительные объявления.
// String не является подвидом Number, поэтому ошибка.
List<? extends Number> list = new ArrayList<String>();  
 
// String не является родительским видом Integer, поэтому ошибка.
ArrayList<? super String> cmp = new ArrayList<Integer>();
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

6.1- Examples with wildcard

WildCardExample1.java

package org.wikitechy.tutorial.generics.w;
 
import java.util.ArrayList;
 
public class WildCardExample1 {
 
    public static void main(String[] args) {
 
        // Список содержащий элементы вида String.
        ArrayList<String> listString = new ArrayList<String>();
 
        listString.add("Tom");
        listString.add("Jerry");
 
        // Список содержащий элементы вида Integer
        ArrayList<Integer> listInteger = new ArrayList<Integer>();
 
        listInteger.add(100);
 
        // Вы не можете объявить:
        ArrayList<Object> list1 = listString; // ==> Error!
 
        // Объект с подстановочным видом параметра.
        // (wildcard parameterized object).
        ArrayList<? extends Object> list2;
 
        // Вы можете объявить:
        // ​​​​​​​
        list2 = listString;
 
        // Или
        list2 = listInteger;
 
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

WildCardExample2.java

package org.wikitechy.tutorial.generics.w;
 
import java.util.ArrayList;
import java.util.List;
 
public class WildCardExample2 {
 
   public static void printElement(List<?> list) {
       for (Object e : list) {
           System.out.println(e);
       }
   }
 
   public static void main(String[] args) {
 
       List<String> names = new ArrayList<String>();
       names.add("Tom");
       names.add("Jerry");
       names.add("Donald");
 
       List<Integer> values = new ArrayList<Integer>();
 
       values.add(100);
       values.add(120);
 
       System.out.println("--- Names --");
 
       printElement(names);
 
       System.out.println("-- Values --");
 
       printElement(values);
 
   }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

6.2- Тип wildcard parameterized не может использовать методы Generics

 шаблон универсального класса
java - джава - учиться java - учебник java -
шаблон универсального класса
- примеры java - java-программы

ValidWildcard1.java

package org.wikitechy.tutorial.generics.w;
 
import java.util.ArrayList;
 
public class ValidWildcard1 {
 
    public static void main(String[] args) {
 
        // Список содержащий элементы вида String.
        ArrayList<String> listString = new ArrayList<String>();
 
        // Использовать метод generic: add(E).
        // Добавить элемент не null в список
        listString.add("Tom");
 
        listString.add("Jerry");
 
        // Добавить элемент null в список.
        listString.add(null);
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

InvalidWildcard1.java

package org.wikitechy.tutorial.generics.w;
 
import java.util.ArrayList;
 
public class InvalidWildcard1 {
 
    public static void main(String[] args) {
  
        // Список с подстановочным видом параметра.
        // (wildcard parameterized type).
        ArrayList<? extends Object> listWildcard = listString;
 
        // Вы не можете использовать метод add(E)
        // с параметром отличающимся от null.
        listWildcard.add("Tom"); // ==> Error!
 
        listWildcard.add("Jerry"); // ==> Error!
 
        // Добавить элемент null в список.
        listWildcard.add(null);
 
    }
 
}
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

6.3- Wildcard не может участвовать в new операторе

  • Wildcard вида параметра(wildcard parameterized type) не является конкретным видом, и не может появиться в операторе new.
// Параметр Wildcard не может участвовать в операторе new.
List<? extends Object> list= new ArrayList<? extends Object>();
нажмите кнопку ниже, чтобы скопировать код. - от - java tutorials - команда

Related Searches to Руководство Java Generics