Heim  >  Artikel  >  Java  >  Detaillierte Erklärung von Generika in Java

Detaillierte Erklärung von Generika in Java

高洛峰
高洛峰Original
2017-01-18 10:54:111316Durchsuche

Die sogenannten Generika: Sie ermöglichen die Angabe von Typparametern beim Definieren von Klassen und Schnittstellen. Dieser Typparameter wird beim Deklarieren von Variablen und beim Erstellen von Objekten bestimmt (d. h. bei der Übergabe tatsächlicher Typparameter, die auch als Typargumente bezeichnet werden können).

Generische Klasse oder Schnittstelle

"Diamond"-Syntax

//定义
 
public interface List<E> extends Collection<E>  
 
public class HashMap<K,V> extends AbstractMap<K,V>  implements Map<K,V>, Cloneable, Serializable 
//使用
 
List<String> list = new ArrayList();
 
//Java7以后可以省略后面尖括号的类型参数
 
List<String> list = new ArrayList<>();

Ableitung einer Unterklasse von einer generischen Klasse

//方式1
 
public class App extends GenericType<String>
 
//方式2
 
public class App<T> extends GenericType<T>
 
//方式3
 
public class App extends GenericType

Pseudo-generisch

Es gibt keine echte generische Klasse. Die JVM kennt die Existenz generischer Klassen und gewöhnlicher Klassen. Daher sind Typparameter in statischen Methoden, statischen Initialisierungsblöcken und statischen Variablen nicht zulässig.
- Die folgenden Methoden sind alle falsch

private static T data;
 
static{
 
    T f;
 
}
 
public static void func(){
 
    T name = 1;
 
}

Das folgende Beispiel kann von der Seite aus überprüfen, dass es keine generische Klasse gibt

public static void main(String[] args){
 
        List<String> a1 = new ArrayList<>();
        List<Integer> a2 = new ArrayList<>();  
    System.out.println(a1.getClass() == a2.getClass());
 
    System.out.println(a1.getClass());
 
    System.out.println(a2.getClass());
 
}

Ausgabe

true
 
class java.util.ArrayList
 
class java.util.ArrayList

Typ-Wildcard

Zunächst muss klar sein, dass, wenn Foo die übergeordnete Klasse von Bar ist, List4ee996100bf04ab273e687539c860625 jedoch nicht die übergeordnete Klasse von Listad40e550a33cb99ea30eede96e03e60e ist Übergeordnete Klassen: Java verwendet „?“, um generische Platzhalter darzustellen. Das heißt, List6b3d0130bba23ae47fe2b8e8cddf0195 stellt die übergeordnete Klasse verschiedener allgemeiner Listen dar. Listen-Generika können keine Elemente festlegen (setzen), sondern nur abrufen (abrufen). Elemente. Da das Programm die Typen in der Liste nicht ermitteln kann, kann es keine Objekte hinzufügen. Das erhaltene Objekt muss jedoch vom Typ Objekt sein.

Die folgenden Methoden kompilieren Fehler:

List<?> list = new ArrayList<>();
 
list.add(new Object());

Einige Ideen:

1. Listf7e83be87db5cd2d9a8a0b8117b38cd4-Objekte können nicht verwendet werden Sprich: Die Listf7e83be87db5cd2d9a8a0b8117b38cd4-Klasse ist keine Unterklasse der Lista87fdacec66f0909fc0757c19f2d2b1d

2. Arrays und Generics sind unterschiedlich: Angenommen, Foo ist ein Untertyp (Unterklasse oder Unterschnittstelle) von Bar, dann ist Foo[] immer noch ein Untertyp von Bar[]; ;Bar>.

3. Um die übergeordnete Klasse verschiedener generischer Listen darzustellen, müssen wir Typ-Wildcards verwenden, um ein Fragezeichen als Typargument zu übergeben , schreiben: Listea8093152e673feb7aba1828c43532094 (bedeutet Liste von Elementen unbekannten Typs). Dieses Fragezeichen (?) wird als Platzhalterzeichen bezeichnet und sein Elementtyp kann mit jedem beliebigen Typ übereinstimmen.

Die Obergrenze der Platzhalter

List31dd03a80537c5dc7749368c753ef149 repräsentiert die übergeordnete Klasse aller generischen SuperType-Listen oder sich selbst. Generics mit Wildcard-Obergrenzen können keine Set-Methoden haben, sondern nur Get-Methoden.

Das Festlegen der Obergrenze für Platzhalter kann die folgenden Probleme lösen: Dog ist eine Animal-Unterklasse und es gibt eine getSize-Methode, um die Anzahl der eingehenden Listen abzurufen. Der Code lautet wie folgt:

abstract class Animal {
    public abstract void run();
}
class Dog extends Animal {
    public void run() {
        System.out.println("Dog run");
    }
}
public class App {
    public static void getSize(List<Animal> list) {
        System.out.println(list.size());
    }
    public static void main(String[] args) {
        List<Dog> list = new ArrayList<>();
        getSize(list); // 这里编译报错
    }
}

Der Grund für den Programmierfehler ist, dass List4cfe4bcd4d110814d5bcb5b26c812079 nicht die übergeordnete Klasse von Lista6240277e46d54dc29cc58bc214c4982 ist. Die erste Lösung besteht darin, den formalen Parameter List4cfe4bcd4d110814d5bcb5b26c812079 in der Methode getSize in List6b3d0130bba23ae47fe2b8e8cddf0195 zu ändern. In diesem Fall ist jedoch bei jedem Abrufen des Objekts eine erzwungene Typkonvertierung erforderlich, was problematischer ist. Die Verwendung der Platzhalterobergrenze löst dieses Problem sehr gut. Sie können List4cfe4bcd4d110814d5bcb5b26c812079 in List6ccbdad665cf442a56ac416f1b31cb89 ändern, und die Kompilierung wird nicht falsch sein und es ist keine Typkonvertierung erforderlich.


Untergrenze des Platzhalterzeichens

List0dfafc26c233a88905402c6a15db8875 stellt die Untergrenze der generischen SubType-Liste dar. Generika mit Platzhalter-Obergrenzen können keine Get-Methoden haben, sondern nur Set-Methoden.

Generische Methoden

Wenn Sie Klassen und Schnittstellen definieren, ohne Typparameter zu verwenden, aber beim Definieren von Methoden selbst Typparameter definieren möchten, bietet JDK1.5 auch Unterstützung für generische Typmethoden . Die Methodensignatur einer generischen Methode enthält mehr Typparameterdeklarationen als die Methodensignatur einer gewöhnlichen Methode. Die Typparameterdeklarationen werden durch Kommas (,) getrennt Modifikatoren und Methodenrückgabewerttypen Das Syntaxformat lautet wie folgt:

修饰符 返回值类型 方法名(类形列表){
 
//方法体
 
}

Generische Methoden ermöglichen die Verwendung von Typparametern, um Typabhängigkeiten zwischen einem oder mehreren Parametern der Methode oder die Typabhängigkeit zwischen Methoden auszudrücken Rückgabewert und Parameter. Wenn keine solche Typabhängigkeit besteht, sollten generische Methoden nicht verwendet werden. Die Kopiermethode von Collections verwendet die generische Methode:

 public static <T> void copy(List<? super T> dest, List<? extends T> src){ ...}

Diese Methode erfordert, dass der src-Typ eine Unterklasse des dest-Typs oder sich selbst sein muss.

Löschen und Konvertieren

In streng generischem Code sollten Klassen mit generischen Deklarationen immer Typparameter tragen. Um jedoch mit altem Java-Code konsistent zu sein, ist es auch erlaubt, Klassen mit generischen Deklarationen ohne Angabe von Typparametern zu verwenden. Wenn für diese generische Klasse kein Typparameter angegeben ist, wird der Typparameter als Rohtyp bezeichnet und verwendet standardmäßig den ersten Obergrenzentyp, der bei der Deklaration des Parameters angegeben wurde.

Wenn ein Objekt mit generischen Informationen einer anderen Variablen ohne generische Informationen zugewiesen wird, werden alle Typinformationen in spitzen Klammern verworfen. Wenn beispielsweise ein Listf7e83be87db5cd2d9a8a0b8117b38cd4-Typ in eine Liste konvertiert wird, wird die Typprüfung der Auflistungselemente der Liste zur Obergrenze der Typvariablen (d. h. Objekt). Diese Situation wird als Löschung bezeichnet.

Beispiel

class Apple<T extends Number>
 
{
 
 T size;
 
 public Apple()
 
 {
 
 }
 
 public Apple(T size)
 
 {
 
  this.size = size;
 
 }
 
 public void setSize(T size)
 
 {
 
  this.size = size;
 
 }
 
 public T getSize()
 
 {
 
  return this.size;
 
 }
 
}
 
public class ErasureTest
 
{
 
 public static void main(String[] args)
 
 {
 
  Apple<Integer> a = new Apple<>(6);    // ①
 
  // a的getSize方法返回Integer对象
 
  Integer as = a.getSize();
 
  // 把a对象赋给Apple变量,丢失尖括号里的类型信息
 
  Apple b = a;      // ②
 
  // b只知道size的类型是Number
 
  Number size1 = b.getSize();
 
  // 下面代码引起编译错误
 
  Integer size2 = b.getSize();  // ③
 
 }
 
}

Ausführlichere Artikel zu Generika in Java finden Sie auf der chinesischen PHP-Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn