Java-Paradigma Diese Dinge (4)

Frühere Artikel zum Java-Paradigma:

Java-Paradigma diese Dinge (1)

Java-Paradigma diese Dinge (2)

Java-Paradigma diese Dinge (3)

1. Wildcard-Erfassung

In einigen Fällen können die Compiler den Typen einer Wildcard schließen, zum Beispiel, kann die Liste als Liste definiert werden <?>, Aber wenn Ausdrücke, die Compiler aus dem Code Auswertung 推断出特定类型, 此场景称为通配符捕获.

Auch die folgenden zwei Verfahren, TEST1 Verfahren , bei dem , nachdem ein Element i extrahiert wird, und dann zu, da der Compiler Typinferenz Mechanismus, i.get(0)abgeleitet ist vom Typ Objekt sein,
Fügen Sie hier eine Bildbeschreibung ein
gegebene Informationen folgt als:
Fügen Sie hier eine Bildbeschreibung ein
für eine Art enthält , die in ihrer 通配符?von Variablen, wie die Parameterliste der Funktion test1 hier, wird der Compiler denken, dass es einige Typen T gibt, so dass für diese T-Liste Liste <T> ist. Es weiß nicht, was Typ T darstellt, aber es kann 为该类型创建一个占位符来指代 T 的类型. 占位符被称为这个特殊通配符的捕获(capture). In diesem Fall wird die Compiler namen “capture#1”zu einem T. zugeordnet

In der Fehlermeldung wird angegeben, dass es häufig vorkommt ?, was darauf hinweist, dass der Typ-Ist-Parameter Object und die Erfassung des Platzhalters (dh die Platzhaltererfassung Nr. 1) beide ?Typen sind und nicht unterschieden werden können, sodass der Kompilierungsfehler gemeldet wird.

⚠️ Hinweis: Jeder Platzhalter in jeder Variablendeklaration erhält eine andere Erfassung. In der generischen Deklaration foo (Pair <?,?> X, Pair <?,?> Y) gibt der Compiler jeweils einen Platzhalter an Der Erfassung der vier Platzhalter wird ein anderer Name zugewiesen, da keine Beziehung zwischen unbekannten Typparametern besteht

Für einige Szenen Wildcard erzeugt aufgenommen wurden, können durch eine interne Wildcard Helper - Klasse erfasst werden ?, die erfasst werden soll T, wie zum Beispiel:

public class WildcardFixed {

    void foo(List<?> i) {
        fooHelper(i);
    }


    // Helper method created so that the wildcard can be captured
    // through type inference.
    private <T> void fooHelper(List<T> list) {
        list.set(0, list.get(0));
    }

}

Zu diesem Zeitpunkt ist in der fooHelper-Methode List<T>der list.get(0)Rückgabewert nicht mehr vom Objekttyp, sondern vom TTyp , da die Parameterliste als Typ deklariert ist . Natürlich können Sie den ermittelten TTyp value ( list.get(0)) in die Liste ( List<T>Typ) einfügen .
Eigentlich ist es so 对原来未知的通配符类型命名,或称作对原来不相容的边界incompatible bounds进行相容处理.


Schauen wir uns noch einmal die test2-Methode an: Der
Fügen Sie hier eine Bildbeschreibung ein
Fehler lautet wie folgt:
Fügen Sie hier eine Bildbeschreibung ein
Fügen Sie hier eine Bildbeschreibung ein
Fügen Sie hier eine Bildbeschreibung ein
Die Eingabeaufforderungssumme <? extends java.lang.Number>wird hier erfasst. <? super java.lang.Number>Die vom Compiler festgelegten Platzhalternamen sind Capture Nr. 2 und Capture Nr. 3.
Nehmen Sie ? extends java.lang.Numberals Beispiel die Summe, dh Typargumente (Integer und Float) und Die vom Compiler automatisch erfassten Typparameter “capture#2”und ? extends java.lang.NumberTypen sind alle Typen, es ist jedoch unmöglich, genau zu bestimmen, welcher Typ (Integer? Oder Float?). Daher kann der Bericht keine geeignete Methode finden.

Stellen Sie eine andere Hilfsmethode bereit, mit der versucht wird, list1.add () nicht als Fehler zu melden:
Fügen Sie hier eine Bildbeschreibung ein
Aus der Fehlermeldung geht hervor, dass es niemanden gibt, der es dem Integer-Typ ermöglicht, das erfasste ? extends java.lang.NumberObjekt zu bestimmen .

Zusammenfassung:
Bei Typvariablen mit Platzhaltern leitet der Compiler automatisch den Typ der Platzhaltertypen in Kombination mit den nachfolgenden Typargumenten ab. Dieses Szenario ist eine Platzhaltererfassung, aber die vom Compiler erfassten Typen können die Ergebnisse manchmal nicht den Erwartungen entsprechen. Definieren Sie eine capture#XXXtransitive Helper-Methode selbst und konvertieren Sie den unbestimmten Erfassungstyp in einen bestimmten Typ T, damit der erwartete Effekt erreicht wird. Aufgrund der ursprünglichen Codelogik können jedoch nicht alle Platzhalter, die Fehler nach der Erfassung melden, durch die Helper-Übertragungsmethode behoben werden Es ist nicht richtig.

2. Paradigmenlöschung

Generika wurden in die Java-Sprache eingeführt, um eine strengere Typprüfung beim Kompilieren zu ermöglichen und die universelle Programmierung zu unterstützen. Um Generika zu implementieren, wendet der Java-Compiler die Typlöschung an auf:

  • Wenn die Typparameter unbegrenzt sind, werden alle Typparameter im generischen Typ durch ihre Grenzen oder ihr Objekt ersetzt, sodass der generierte Bytecode nur normale Klassen, Schnittstellen und Methoden enthält.
  • Fügen Sie bei Bedarf Typkonvertierungen ein, um die Typensicherheit zu gewährleisten.
  • Brückenmethoden werden generiert, um den Polymorphismus in erweiterten generischen Typen zu erhalten.

Durch das Löschen von Typen wird sichergestellt, dass keine neuen Klassen für parametrisierte Typen erstellt werden, sodass für Generika kein Laufzeitaufwand anfällt.

Beim Löschen des Typs löscht der Java-Compiler alle Typparameter und ersetzt sie durch die erste Grenze, wenn die Typparameter begrenzt sind. Wenn der Typparameter unbegrenzt ist, wird er durch Object ersetzt.

那为什么Java编译器要进行类型擦除呢?只是为了不为参数化类型创建新类来不产生运行时开销吗?

Herkunft : Java hatte zunächst keine Generika und später 1.5 Generika 为了能向前兼容(旧版本的jvm能解释运行新版本的.class文件)所以就采用了伪泛型——“泛型擦除”und wurde beibehalten.

Prinzip : Generische Informationen sind nur in der Code-Kompilierungsphase vorhanden. Nach dem 进入 JVM 之前,与泛型相关的信息会被擦除掉Löschen werden sie zum ursprünglichen Typ (entfernen Sie <T>, löschen Sie das T in der Methode in Object). Beispielsweise werden generische <T> in generische Informationen gelöscht. Es sollte auch beachtet werden, dass verschiedene Platzhalter auf unterschiedliche Weise gelöscht werden:

Mantra: [Speichern in: Nehmen Sie die Grenze herunter; Nehmen Sie heraus: Nehmen Sie die obere Grenze ein] - oder - [Speichern Sie ein, nehmen Sie an]

  • Wenn der generische Typ als eingehender Parameter der Methode verwendet wird, wird er zu diesem Zeitpunkt durch die Untergrenze des Wildtyps ersetzt, z. B. die Methode add

  • Wenn das Generikum als Rückgabeparameter der Methode verwendet wird, wird diese Zeit durch die Obergrenze des Platzhalter-Generikums ersetzt, z. B. die get-Methode

List<? extends Integer> list1 = new ArrayList<Integer>();
list1.add(null); // 此时传入取<? extends Integer> 下界————无 所以只能传null,否则报错
Integer integer1 =  list1.get(0); // // 此时返回取<? extends Integer> 上界————Integer

List<? super Integer> list2 = new ArrayList<Integer>();
list2.add(111); // 此时传入取<? super Integer> 下界——————Integer
Integer integer2 =  (Integer) list2.get(0); // // 此时返回取<? super Integer> 上界————Object

Referenz:
Artikel der offiziellen Website zur Wildcard-Erfassung: Eine chinesische Übersetzung entsprechend Wildcard-Erfassung und Hilfsmethoden
: Java ™ -Tutorial (generische Wildcard-Erfassung und Hilfsmethode)
Einführung der offiziellen Website in die Typlöschung: Eine chinesische Übersetzung entsprechend Typlöschung
: Java ™ Tutorial (Typ Löschen)

Java-Theorie und -Praxis: Verwenden von Platzhaltern zur Vereinfachung von Generika, Verwenden von
generischen Java-Unterschieden und generisches Löschen Detailliertes
Java ™ -Tutorial (Einschränkungen von Generika)

Veröffentlichte 82 Originalartikel · Gefällt mir 86 · Besuchen Sie 110.000+

Ich denke du magst

Origin blog.csdn.net/unicorn97/article/details/102053961
Empfohlen
Rangfolge