Die Anleitung zu Java Generics

1- Warum Java Generics?

Generics wird ab der Java Version 5 eingeführt. Vor der Definition von Generics sehen wir ein Java Code vor der java Version 5.
Im Beispiel ist ArrayList eine Liste, in der Sie hinzufügen, löschen, ändern und in die Elemente der Liste zugreiffen können.
BeforeJ5Example.java
package org.o7planning.tutorial.generics;

import java.util.ArrayList;

public class BeforeJ5Example {

	public static void main(String[] args) {

		// Ein Objekt ArrayList erstellen (eine Liste).
		// Um den Name des Benutzer zu enthalten.
		ArrayList userNames = new ArrayList();

		// Die String in die Liste einfügen.
		userNames.add("tom");
		userNames.add("jerry");

		// Sie fügen unabsichtilich ein Nicht-String-Typ Element in die Liste ein.
		// (das erlaubt ganz nicht).
		userNames.add(new Integer(100));

		// Und das erste Element nehmen
		// Das ist ein Objekt (aber Sie kennen, dass es ein String ist)
		// ==> tom
		Object obj1 = userNames.get(0);

		// Cast zu String.
		String userName1 = (String) obj1;

		System.out.println("userName1 = " + userName1);

		// Das 2. Element nehmen
		// (Sie kenen, das ist String)
		// ==> jerry
		String userName2 = (String) userNames.get(1);

		System.out.println("userName2 = " + userName2);

		// Das 3.Element nehmen und Cast zum String machen.
		// (Eigentlich ist es ein Integer).
		// (Der Fehler vom Cast passiert hier).
		String userName3 = (String) userNames.get(2);

		System.out.println("userName3 = " + userName3);
	}

}
Ein Java Situation im der Java vor Version 5

Sie erstellen ein Object ArrayList zum Zweck der Containier die String elemente. Aber in irgendwo des Programm addieren Sie in die Liste ein nicht String Object (machbar sein) und wenn Sie die Elemente nehmen und sie ins String verwandeln, wird eine Ausnahme geworfen
  • TODO (Image)
Im Java 5 wird der Begriff G enerics eingeführt.  Mit der Hilfe von Generics können Sie ein Object ArrayList erstellen, die nur die String Element Type enthalten können, darf keine anderen Elemente Type enthalten.
J5Example.java
package org.o7planning.tutorial.generics;

import java.util.ArrayList;

public class J5Example {

	public static void main(String[] args) {

		// Ein ArrayList erstellen (Eine Liste)
		// Die Liste erlaubt, die String-Typ Elemente zu enthalten.
		ArrayList<String> userNames = new ArrayList<String>();

		// Die String in die Liste einfügen.
		userNames.add("tom");
		userNames.add("jerry");

		// Sie können die Nicht-String Elemente in die Liste nicht einfügen 
		// (Der Fehler bei der Kompilierung)
		userNames.add(new Integer(100)); // Compile Error!

		// Sie brauchen cast vom Element nicht
		String userName1 = userNames.get(0);

		System.out.println("userName1 = " + userName1);

	}

}
Wenn Sie ein Object ArrayList<String> erstellen, enthaltet es nur die String Elemente Type, Der Compiler von Java genehmigt nicht, dass dieses Object die anderen Elemente Type (keine String Elemente) enthaltet.

2- Das Typ Generic für Class & Interface

2.1- Generics Class

Das unten Beispiel stellt eine Class generics dar. KeyValue ist eine class generics, die einen Schlüsselpaar und die Wert (key/value) erhaltet.
 
KeyValue.java
package org.o7planning.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;
   }

}
K, V in der class  KeyValue<K,V> werden als Parameter generics genannt. es ist eine Reference type. Bei der Benutzung dieses class müssen Sie den konkreten Parameter bestimmten.

Sehen Sie das Beispiel für die Benutzung des class KeyValue.
 
KeyValueDemo.java
package org.o7planning.tutorial.generics.ci;

public class KeyValueDemo {

	public static void main(String[] args) {

		// Ein Objekt KeyValue erstellen
		// Integer: Die Telefonenummer (K = Integer)
		// String: Der Name des Benutzer. (V = String).
		KeyValue<Integer, String> entry = new KeyValue<Integer, String>(12000111, "Tom");

		// Java versteht, das Zurückgabe-Typ ist Integer (K = Integer).
		Integer phone = entry.getKey();

		// Java versteht, das Zurückgabe-Typ ist String (V = String).
		String name = entry.getValue();

		System.out.println("Phone = " + phone + " / name = " + name);
	}

}
Beispiel

2.2- Die Erbe der Klasse Generics

Ein von class generics ausgeweitertes class kann Parameter generics klar bestimmen, still halten oder zusätzen

Beispiel 1

PhoneNameEntry.java
package org.o7planning.tutorial.generics.ci;

// Die Klasse verlängert aus der Klasse KeyValue<K,V>.
// Und bestimmt K,V:
// K = Integer  (Die Telefonenummer).
// V = String   (der Name).
public class PhoneNameEntry extends KeyValue<Integer, String> {

	public PhoneNameEntry(Integer key, String value) {
		super(key, value);
	}

}
Beispiel von der Benutzung PhoneNameEntry:
PhoneNameEntryDemo.java
package org.o7planning.tutorial.generics.ci;

public class PhoneNameEntryDemo {

	public static void main(String[] args) {

		PhoneNameEntry entry = new PhoneNameEntry(12000111, "Tom");

		// Java versteht, das Zurückgabe-Typ ist Integer.
		Integer phone = entry.getKey();

		// Java versteht, das Zurückgabe-Typ ist String.
		String name = entry.getValue();

		System.out.println("Phone = " + phone + " / name = " + name);

	}

}

Beispiel 2

StringAndValueEntry.java
package org.o7planning.tutorial.generics.ci;

// Die Klasse verlängert aus der Klasse KeyValue<K,V>.
// bestimmen, das Parameter Typ <K> ist String.
// Das Parameter Typ Generic <V> halten
public class StringAndValueEntry<V> extends KeyValue<String, V> {

	public StringAndValueEntry(String key, V value) {
		super(key, value);
	}

}
Beispiel von der Benutzung von  StringAndValueEntry class:
StringAndValueEntryDemo.java
package org.o7planning.tutorial.generics.ci;

public class StringAndValueEntryDemo {

	public static void main(String[] args) {

		// (Code des Arbeitnehmer, der Name des Arbeitnehmer).
		// V = String (Der Name des Arbeitnehmer)
		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);

	}

}

Beispiel 3:

KeyValueInfo.java
package org.o7planning.tutorial.generics.ci;

// Die Klasse verlängert aus der Klasse KeyValue<K,V>
// Sie hat ein mehr Parameter 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;
	}

}

2.3- Generics Interface

Ein Interface hat Parameter Generics:
GenericInterface.java
package org.o7planning.tutorial.generics.ci;

public interface GenericInterface<G> {

 
  public G doSomething();
 
}
Beispiel: Ein Class für Interface Durchführung aufs...
GenericInterfaceImpl.java
package org.o7planning.tutorial.generics.ci;

public class GenericInterfaceImpl<G> implements GenericInterface<G>{

   private G something;
   
   @Override
   public G doSomething() {
       return something;
   }

}

2.4- Java unterstützt Generic Throwable nicht

Sie können ein class generic als den Nachwuchs von Throwable nicht erstellen. Java unterstützt bei der Erstellung dieser class nicht
Warnung der Error von dem Complier:
- The generic class MyException<E> may not subclass java.lang.Throwable
Java unterstützt bei der Erstellung eines class Throwable generic, weil es nicht nutzlich ist. Der Grund ist, dass die Information Generic nur den Complier der Code Prüfung von dem Entwickler benutzt. Bei der Zeitpunkt der Java Funktionierung findet nicht die Information Generic statt. Ein Object von Mistake<Account> oder  Mistake<User> ist die Object type von  Mistake.
} catch( Mistake<Account> ea) {
    // Wenn die Ausnahme Mistake passiert, wird das Block implementiert.
    ...
} catch( Mistake<User> eu) {
     // Das Block wird nie implementiert
    ...
}

3- Die Methode von generics

Ein Method in class oder interface wird generify 
MyUtils.java
package org.o7planning.tutorial.generics.m;

import java.util.ArrayList;

import org.o7planning.tutorial.generics.ci.KeyValue;

public class MyUtils {

	// <K,V> : sagen, die Methode hat 2 Parameter Typ  K,V
	// Die Methode gibt ein K Typ Objekt zurück.
	public static <K, V> K getKey(KeyValue<K, V> entry) {
		K key = entry.getKey();
		return key;
	}

	// <K,V> : sagen, die Methode hat 2 Parameter Typ K,V
	// Die Methode gibt ein V Typ Objekt zurück.
	public static <K, V> V getValue(KeyValue<K, V> entry) {
		V value = entry.getValue();
		return value;
	}

	// ArrayList<E>: Die Liste der E-Typ Elemente.
	// Die Methode gibt ein E Typ Objekt zurück.
	public static <E> E getFirstElement(ArrayList<E> list) {
		if (list == null || list.isEmpty()) {
			return null;
		}
		E first = list.get(0);
		return first;
	}

}
Beispiel von Benutzung des Method generics:
MyUtilsDemo.java
package org.o7planning.tutorial.generics.m;

import java.util.ArrayList;

import org.o7planning.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);

		// Eine Liste der Element vom Typ KeyValue<Integer,String>.
		ArrayList<KeyValue<Integer, String>> list = new ArrayList<KeyValue<Integer, String>>();

		// Die Elemente in die Liste einfügen.
		list.add(entry1);
		list.add(entry2);

		KeyValue<Integer, String> firstEntry = MyUtils.getFirstElement(list);

		System.out.println("Value = " + firstEntry.getValue());
	}

}

4- Der Constructor Generic

Manchmal möchten Sie ein Object Generic: erstellen
// Das Generic Objekt erstellen.
T t = new T(); // Error
Die Erstellung eines generic Object wie oben ist nicht genehmigt. denn <T> ist nicht bei der Java Durchführung vorhanden. Es hat nur die Bedeutung mit dem Complier der Code Prüfung von dem Entwickler. Alle Typen <T> sind gleich, und werden als Object bei Java Durchführung verstanden.

Sie sollen Java ein Object Class<T> für die Erstellung eines Object generic bringen. Java wird das object <T> bei der runtime durch Java Reflection.erstellt
Bar.java
package org.o7planning.tutorial.generics.o;

import java.util.Date;

public class Bar {

	// Die Klasse muss einen Default Constructor haben
	public Bar() {

	}

	public void currentDate() {
		System.out.println("Now is: " + new Date());
	}

}
MyGeneric.java
package org.o7planning.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;
   }
}
MyGenericDemo.java
package org.o7planning.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();
   }
}

5- Der Array Generic

Sie können ein Array Generic melden, aber Sie können kein Array generic erstellen 
// Sie können ein generic Array erklären.
T[] myarray;

// Aber das generic Array nicht  initializieren können.
// (Das ist nicht erlaubt).
T[] myarray = new T[5];  // Error!
Beispiel
GenericArray.java
package org.o7planning.tutorial.generics.a;

public class GenericArray<T> {

	private T[] array;

	// Contructor.
	public GenericArray(T[] array) {
		this.array = array;
	}

	public T[] getArray() {
		return array;
	}

	// Das letzte Element zurückgeben
	public T getLastElement() {
		if (this.array == null || this.array.length == 0) {
			return null;
		}
		return this.array[this.array.length - 1];
	}

}
GenericArrayDemo.java
package org.o7planning.tutorial.generics.a;

public class GenericArrayDemo {

	public static void main(String[] args) {

		// Ein Array vom Strings.
		String[] names = new String[] { "Tom", "Jerry" };

		GenericArray<String> gArray = new GenericArray<String>(names);

		String last = gArray.getLastElement();
		
		System.out.println("Last Element = " + last);
	}

}
Zurück zum Problem: warum unterstützt Java bei der Erstellung eines Array Generic:nicht
// Warum unterstützt Java die Initialization vom generic Array nicht?
T[] genericArray = new T[10]; // Error!
Der Grund: die generic Type ist nicht bei der Runtime vorhanden. List<String> oder  List<Integer> sind List. Generic ist gültig nur mit dem Compiler zur Code Prüfung von Entwickler. Es bedeutet,dass der Compiler von java <T> klar wissen braucht um new T[10];.zu komplieren. Sonst sehen es standardmäßig T als ein Object .Dann
// Angenommen, Java darf ein Generic Array initializieren:
T[]  tarray = new T[10];

// Bei der Zeitpunkt von der Kompilierung (Compile-time)
// Der Kompilier sieht  <T> als ein Object.
// Der Befehl oben ist äquivalent wie:
T[] tarray  = new Object[10];

// Ber der Zeitpunkt der Durchführung der Applikation bestimmen Sie <T> als String.
// Das bedeutet, dass:
String[] tarray = new Object[10];

// Das oben wird nicht erlaubt. Der Grund liegt darin:
// Type mismatch: cannot convert from Object[] to String[]
Sie sollen Java den Object Class<T> übertragen wenn Sie ein Array Generic erstellen möchten. Das hilft java bei der Erstellung eines Array generic bei runtime durch Java Reflection. Sehen Sie das Beispiel
GArray.java
package org.o7planning.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;
  }

}
GArrayDemo.java
package org.o7planning.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;
   }

}

6- Generics mit der Vertretungszeichen

In der Generic Code ist die Fragezeichen ein Vertreter (wildcard) genannt. Es vertretet die nicht klare Type. Ein wildcard  parameterized type ist ein Fall der Generic type, wo es gibt mindesten ein Parameter type, das ist wildcard
Beispiel von der wildcard parameterized 
  • Collection<?>
  • List<? extends Number>
  • Comparator<? super String>
  • Pair<String,?>.
Die wildcard Zeichen können in eine Reihe von Situation benutzt wie Parameter type, field, oder lokale Variable, oder manchmal wie die Rückgegebenen Daten (wird im Beispiel klar erläutert). Die wildcard werden nie wie ein Parameter für die Aufruf von Methode Generic, die Erstellung des Object class generic oder supertype benutzt
Die wildcard Zeichen, die in der unterschiedlichen Position liegen, haben die unterschiedlichen Bedeutung
  • Collection<?> bezeichnet eine Kollektion der allen Objektstypen.
  • List<? extends Number> bezeichnet eine Liste, wo die Element das Number Typ oder das Typ von Kinder vom Number sind
  • Comparator<? super String> bezeichnet einen Vergleich (Comparator), in dem der Parameter String oder der Vater vom String ist.
Ein Parameter type der wildcard Zeichen ist keine konkrete Type für die Entstehung in einer Operator new. Es schlägt nur die Durchführung der wertvollen Type in irgendwelche bestimmten Situation durch generics java vor. 
  • Beispiel
Collection<?> coll = new ArrayList<String>();

// Eine Kollektion enthaltet nur das Number Typ oder Subtyp vom Number 
List<? extends Number> list = new ArrayList<Long>();

// Ein Objejt hat  wildcard parameterized type)
Pair<String,?> pair = new Pair<String,Integer>();
Einige Anmeldungen sind nicht gültig
// String ist kein SubTyp von Number, so den Fehler.
List<? extends Number> list = new ArrayList<String>();  

// String ist kein VaterTyp von Integer, so den Fehler
ArrayList<? super String> cmp = new ArrayList<Integer>();

6.1- Zum Beispiel: wildcard

WildCardExample1.java
package org.o7planning.tutorial.generics.w;

import java.util.ArrayList;

public class WildCardExample1 {

	public static void main(String[] args) {

		// Eine Liste von den String Elemente.
		ArrayList<String> listString = new ArrayList<String>();

		listString.add("Tom");
		listString.add("Jerry");

		// Eine Liste von den Integer Elemente
		ArrayList<Integer> listInteger = new ArrayList<Integer>();

		listInteger.add(100);

		// Sie können nicht erklären:
		ArrayList<Object> list1 = listString; // ==> Error!

		// Ein wildcard parameterized object).
		ArrayList<? extends Object> list2;

		// Sie können anmelden:
		list2 = listString;

		// Oder
		list2 = listInteger;

	}

}
WildCardExample2.java
package org.o7planning.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);

   }

}

6.2- Das Wildcard Projekt kann die generic Methode nicht benutzen

ValidWildcard1.java
package org.o7planning.tutorial.generics.w;

import java.util.ArrayList;

public class ValidWildcard1 {

	public static void main(String[] args) {

		// Eine Liste von String Elemente.
		ArrayList<String> listString = new ArrayList<String>();

		// Die Methode generic: add(E) benutzen.
		// Ein Nicht-Null Element in die Liste einfügen
		listString.add("Tom");

		listString.add("Jerry");

		// Ein Null-Element in die Liste einfügen.
		listString.add(null);
	}

}
InvalidWildcard1.java
package org.o7planning.tutorial.generics.w;

import java.util.ArrayList;

public class InvalidWildcard1 {

	public static void main(String[] args) {
 
		// Eine Liste vom wildcard parameterized type).
		ArrayList<? extends Object> listWildcard = listString;

		// Sie können die Methode add(E) nicht benutzen, die mit dem Nicht-Null Wert nicht ist
		listWildcard.add("Tom"); // ==> Error!

		listWildcard.add("Jerry"); // ==> Error!

		// Ein Null Element einfügen
		listWildcard.add(null);

	}

}

6.3- Wildcard kann an den Operator new nicht teilnehmen

EIne wildcard parameterized type ist nicht die konkrete Type und es kann in die Operator new nicht scheinen
// Wildcard kann an den Operator new nicht teilnehmen.
List<? extends Object> list= new ArrayList<? extends Object>();

View more categories: