Homogene Realisierung von Generics in Java ?

John_Sace

Mitglied
Guten Tag,
mich beschäfftigt zur Zeit ein Thema sehr.
Und zwar wie die Generics in Java umgesetzt sind. Ich habe gelesen ,dass in Java die Generics homogen realisert werden.
So fern ich es verstanden habe erzeugt Java für jeden gernerischen Typen genau eine Klasse in die generischen Typen durch Object ersetzt werden.
Dies führt zu einer Typlöschung.
Leider verstehe ich nicht ganz was mit der erzeugung von nur einer generischen Klasse gemeint ist oder wieso es zu einer Typlöschung kommt.
Woher weiß der Compiler zur Laufzeit was nun der spezifische Typ ist wenn dieser von zb. <String> zu <Object> ersetzt wurde.
Und wie würde eine Heterogene Realisierung aussehen ?
Ich freu mich über jede Antwort :)
 

John_Sace

Mitglied
Ich denke hier ist dein Problem. Der Compiler macht ja nichts zur Laufzeit, er kompiliert einfach nur - also javac. Zur Laufzeit ist der Compiler längst fertig und dann gibt es den generischen Typ nicht mehr.
Type erasure: https://docs.oracle.com/javase/tutorial/java/generics/erasure.html
Danke für die Antwort :)
Leider wurde es mir noch immer nicht ganz klarer. Nur die Frage kann ich nun korekter stellen : Woher weiß der Compiler was nun der spezifische Typ ist ?
 

KonradN

Super-Moderator
Mitarbeiter
Woher weiß der Compiler was nun der spezifische Typ ist ?
Der Compiler arbeitet mit dem Source und im Source steht der spezifische Typ. Weiterhin erzeugt er den Bytecode und in dem wird der spezifische Typ entfernt. Das ist in dem Link zu type erasure beschrieben.

Zur Laufzeit (Das ist nicht der Java Compiler sondern die Java Laufzeitumgebung!) wird nur mit dem Bytecode gearbeitet bei dem es dann den spezifischen Typ so nicht mehr gibt.

Siehe evtl. auch
Type Erasure in Java - GeeksforGeeks
Type Erasure in Java Explained | Baeldung
oder suche selbst einmal nach "java type erasure"
 

John_Sace

Mitglied
Der Compiler arbeitet mit dem Source und im Source steht der spezifische Typ. Weiterhin erzeugt er den Bytecode und in dem wird der spezifische Typ entfernt. Das ist in dem Link zu type erasure beschrieben.

Zur Laufzeit (Das ist nicht der Java Compiler sondern die Java Laufzeitumgebung!) wird nur mit dem Bytecode gearbeitet bei dem es dann den spezifischen Typ so nicht mehr gibt.

Siehe evtl. auch
Type Erasure in Java - GeeksforGeeks
Type Erasure in Java Explained | Baeldung
oder suche selbst einmal nach "java type erasure"
Danke für die ausführliche Antwort :)
Es zerbricht mir tatsächlich bisschen den Kopf. Also ist die Typ löschung im Grunde keine Löschung sonder ein Ersetzen durch den Typ Object. Gelöscht wird der Typ im Grunde ja nicht weil dieser sich ja noch für eventuell benötigte Casts gemerkt wird oder ?
 

distinct

Mitglied
Na ja, vermutlich, eine nicht finale Klasse als Typ-Parameter bzw. Wildcards.

Ich muss aber gestehen, mich nicht zu 100 % damit auszukennen.
 

KonradN

Super-Moderator
Mitarbeiter
Im ersten Link ist in Kürze sehr genau gesagt, was mit type erasure gemacht wird.

A) type Parameter werden ersetzt (und damit verschwindet der original Type … das kann also durchaus auch als Löschen bezeichnet werden. Das wäre ja auch die Übersetzung von erasure.)
B) es werden - wo notwendig - Type casts eingefügt
C) bridge methods werden eingefügt bei der Vererbung von generischen Typen
 

distinct

Mitglied
Aus beispielsweise

Java:
package org.example;

import java.util.ArrayList;

public class TestClazz {
    public static void main(String[] args) {
        ArrayList<Integer> list_a = new ArrayList<>();
        list_a.add(42);
        System.out.println(list_a);
        ArrayList list_b = new ArrayList();
        list_b.add("Hallo");
        System.out.println(list_b);
        ArrayList<Object> list_c = new ArrayList<>();
        list_c.add("Welt");
        list_c.add(123);
        System.out.println(list_c);
    }
}

wird "einfach":

Code:
Compiled from "TestClazz.java"
public class org.example.TestClazz {
  public org.example.TestClazz();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #7                  // class java/util/ArrayList
       3: dup
       4: invokespecial #9                  // Method java/util/ArrayList."<init>":()V
       7: astore_1
       8: aload_1
       9: bipush        42
      11: invokestatic  #10                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      14: invokevirtual #16                 // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
      17: pop
      18: getstatic     #20                 // Field java/lang/System.out:Ljava/io/PrintStream;
      21: aload_1
      22: invokevirtual #26                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      25: new           #7                  // class java/util/ArrayList
      28: dup
      29: invokespecial #9                  // Method java/util/ArrayList."<init>":()V
      32: astore_2
      33: aload_2
      34: ldc           #32                 // String Hallo
      36: invokevirtual #16                 // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
      39: pop
      40: getstatic     #20                 // Field java/lang/System.out:Ljava/io/PrintStream;
      43: aload_2
      44: invokevirtual #26                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      47: new           #7                  // class java/util/ArrayList
      50: dup
      51: invokespecial #9                  // Method java/util/ArrayList."<init>":()V
      54: astore_3
      55: aload_3
      56: ldc           #34                 // String Welt
      58: invokevirtual #16                 // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
      61: pop
      62: aload_3
      63: bipush        123
      65: invokestatic  #10                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      68: invokevirtual #16                 // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
      71: pop
      72: getstatic     #20                 // Field java/lang/System.out:Ljava/io/PrintStream;
      75: aload_3
      76: invokevirtual #26                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      79: return
}

Wie man jetzt sehen kann, haben alle drei Lists scheinbar die gleiche Gestalt. Dh, die Checks finden nur zur Übersetzungszeit statt.
 

KonradN

Super-Moderator
Mitarbeiter
Nein, da wird adaptiert bzw. transferiert. Löschung ist nur ne umgangssprachliche Beschreibung dafür.
Zum Glück ist nicht der Tobias derjenige, der alles festlegt.

a) Die Wortwahl wurde über die Java Language Specification festgelegt. Und da ist in 4.6 "Type Erasure" festgelegt worden. Ob nun der englische Begriff "erasure" passend ist oder nicht mag man gerne diskutieren, aber das führt zu nichts. Wir haben eine klare Begriffsbestimmung und diesen Begriff nutzt man. Und wenn man dann diesen Begriff übersetzen will um einen Deutschen Begriff zu nutzen, dann wäre die Übersetzung eher Löschung oder Radierung und eben nicht Substituierung, Ersetzung oder ähnliches.

b) @John_Sace nutzt als Anfänger eher Umgangssprache. Daher sollte die Verwendung des Begriffes Löschung also auch aus Deiner Sicht ok sein. Danke für diese Bestätigung und Einsicht.

Dürfte durch dynamische Typbindung geschehen. Der hier hat was drüber geschrieben: https://www.scaler.com/topics/dynamic-binding-in-java/

Edit: Auch "Laufzeit-Polymorphismus" genannt ...
Aber auch für Dich ist wichtig: Das ist nicht der Compiler! "Woher weiß der Compiler zur Laufzeit was nun der spezifische Typ" - der Compiler weiss zur Laufzeit gar nichts, denn der (Java) Compiler ist nur zur Compilezeit aktiv! Und wenn man den JIT betrachtet: Der JIT übersetzt lediglich Bytecode weiter - den interessiert kein spezifischer Typ.

Und nein - dynamic binding hat mit Generics erst einmal nichts zu tun! Das wird z.B. deutlich, wenn Du mal versuchst in einer Klasse die folgenden zwei Methoden zu haben:
Java:
    public void someMethod(java.util.List<Integer> param) {}
    public void someMethod(java.util.List<String> param) {}

Auf Grund der type erasure haben die Methoden die gleiche Signatur was dann auch die Fehlermeldung direkt aussagt:
name clash: someMethod(java.util.List<java.lang.String>) and someMethod(java.util.List<java.lang.Integer>) have the same erasure
 

KonradN

Super-Moderator
Mitarbeiter
Um das mit der Compilezeit und Laufzeit und der Type Erasure einmal etwas zu verdeutlichen.

Wir machen mal einfach eine Testklasse:
Java:
import java.util.ArrayList;
import java.util.List;

public class TestList {
    public static List<Integer> content = new ArrayList<>();
}

Darauf können wir dann zugreifen:
Java:
public class TestApp {
    public static void main(String[] args) {
        TestList.content.add(17);
    }
}

Diesen Code können wir dann übersetzen mit dem Compiler und dann mit der Java Virtual Machine ausführen:
Code:
konrad@MBP-von-Konrad java % javac TestApp.java TestList.java
konrad@MBP-von-Konrad java % java TestApp
konrad@MBP-von-Konrad java %

Soweit noch alles ok.

Nun ändern wir aber TestList und machen content zu einer List<String> und übersetzen nur die TestList.java:

Und auch mit der neuen Klasse:
Java:
import java.util.ArrayList;
import java.util.List;

public class TestList {
    public static List<String> content = new ArrayList<>();
}
können wir die TestApp laufen lassen:
Code:
konrad@MBP-von-Konrad java % javac TestList.java
konrad@MBP-von-Konrad java % java TestApp
konrad@MBP-von-Konrad java %

Das liegt an der Type Erasure, denn aus List<String> ist einfach ein List<Object>. Der Typparameter ist also "entfernt" worden. (Und hier wird mir auch gerade klar, wieso da Type Erasure als Name gewählt wurde. Der Typparameter wird entfernt. Die generische Klasse List<> verhält sich dann unter dem Strich so, wie die Klasse List vor Einführung der Generics. Aber das nur so ganz am Rande. Ich mag damit falsch liegen, aber sowas würde Sinn machen.)

Aber natürlich lässt sich der Code nicht mehr Übersetzen. Auch wenn der Bytecode funktionieren würde. Aber bei einer Übersetzung erhält man nun natürlich:
Code:
konrad@MBP-von-Konrad java % javac TestApp.java TestList.java
TestApp.java:3: Fehler: Inkompatible Typen: int kann nicht in String konvertiert werden
        TestList.content.add(17);
                             ^
Hinweis: Einige Meldungen wurden vereinfacht. Wiederholen Sie die Kompilierung mit -Xdiags:verbose, um die vollständige Ausgabe abzurufen
1 Fehler
konrad@MBP-von-Konrad java %

Das ist also eine kleine Spielerei, die evtl. bei dem Verständnis etwas hilft. Denn der ByteCode entspricht unter dem Strich dem:
Java:
import java.util.ArrayList;
import java.util.List;

public class TestList {
    public static List<Object> content = new ArrayList<>();
}

bzw. dem (Um das "Löschen" zu zeigen):
Java:
import java.util.ArrayList;
import java.util.List;

public class TestList {
    public static List content = new ArrayList();
}

Aber da der Compiler Generics natürlich kennt und das für Typechecks verwendet wird, gibt es nun eine Warnung, dass der Aufruf unchecked ist. Daher müsste man die Warnung unterdrücken, wenn man die List ohne Generic ansprechen möchte:
Java:
public class TestApp {
    @SuppressWarnings("unchecked")
    public static void main(String[] args) {
        TestList.content.add(17);
    }
}
Das aber nur als Hinweis um hier etwas damit zu spielen, was da passiert. Selbstverständlich gibt man die Typ Parameter an und sorgt so dafür, dass der Compiler die Typen prüfen kann!
 

KonradN

Super-Moderator
Mitarbeiter
Mir scheint, du legst mir wieder Sachen in den Mund, die ich so nicht gesagt hatte ...
Du hast ganz klar eine Frage beantwortet. Und das ist definitiv falsch. Kannst Du selbst nachsehen, aber ich kann es Dir auch schnell als Bild einbinden:
Bildschirmfoto 2023-08-17 um 21.57.44.png

Somit lege ich Dir keine Sachen in den Mund. Wenn jemand fragt: "Was ist 2 + 2" und Du antwortest 5. Dann wird diese Antwort falsch sein. Da kannst Du noch so sehr behaupten, dass Du auf eine andere Frage wie 2 + 3 antworten wolltest. Du hast auf die Frage "was ist 2 + 2" mit 5 geantwortet und das ist schlicht nicht "Sachen in den Mund legen". Du magst da etwas anderes gelesen oder verstanden haben. Aber dann solltest Du an deiner Kommunikation arbeiten.

Aber das werde ich nicht weiter vertiefen. Solche sinnlosen Diskussionen hatten wir schon viel zu oft und daher ist klar, wie sinnlos so eine Diskussion ist.
 

KonradN

Super-Moderator
Mitarbeiter
Aber natürlich lässt sich der Code nicht mehr Übersetzen.
Evtl. zu genau diesem Punkt paar Worte mehr, da dies der wirklich wichtige Punkt ist:

Durch Generics bekommen wir zur Compilezeit eine Typüberprüfung! Das ist also speziell für den Compiler gemacht und gibt uns beim Übersetzen unseres Codes eine deutlich größere Typsicherheit.

Das ist der wichtige Punkt, der hier verstanden werden sollte.

Das wird auch deutlich, wenn man sich die Generics Einführungen anschaut. Also z.B. bei The Basics of Java Generics | Baeldung:
JDK 5.0 introduced Java Generics with the aim of reducing bugs and adding an extra layer of abstraction over types.

Es geht um einen "extra layer", also einer zusätzlichen Schicht, die auf das bisherige Java gelegt wurde. Vorher war alles bei sowas einfach ein Object. Durch diese Schicht haben wir nun im Code bei uns eine Typsicherheit und unser Code mit Generics wird sozusagen in etwas umgesetzt, dass ohne Generics auskommt.

Aber hier gilt: Das ist eine stark vereinfachte Sicht! Wir haben hier jetzt speziell den letzten Punkt bei der Beschreibung von type erasure komplett ignoriert!

Wichtig ist hier also der Unterschied zu z.B. Templates bei C++. Man erstellt in C++ ein Template und wenn das genutzt wird, dann entsteht tatsächlich eine konkrete Implementierung von dem Template. Also auch wenn da teilweise von "Generics" gesprochen wird (z.B. bei Generics in C++ - GeeksforGeeks), ist das doch eine komplett andere Sache (und man sollte da von Templates reden - das ist ja auch das Keyword).
 

Oneixee5

Top Contributor
Möglicherweise kann man type erasure besser verstehen wenn man davon ausgeht, das in Java eig. alles ein Object ist(primitive kommen hier ja nicht in Frage). Wenn ich also den konkreten Typen entferne dann ist es trotzdem ein Object. Also man muss den Typen nicht ändern um auf Object zu kommen. Implizit ist es das immer.

Du solltest auch davon ausgehen, das Generics einfach ein später Zusatz in Java sind. Früher (war nicht alles besser) gab es z.B. nur List ohne einen generischen Typen. In der List waren immer nur Object's. Heute ist das im Prinzip immer noch so. Nur das man für den Programmierer ein Hilfsmittel im Compiler geschaffen hat. List war quasi nicht typisiert - was man aber in Java, als typisierte Sprache, haben möchte. Man hat früher nicht nur eine Unmenge Cast's durchführen müssen, sondern musste auch selbst dafür sorgen, dass man immer nur passende Objekte in eine List gefüllt hat. Jetzt ist der Compiler (und damit indirekt die IDE) weitgehend in der Lage zu erkennen welcher Typ in eine Liste passt und auch wieder herauskommt.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
A Methoden Gedanken Anstöße zur Realisierung zweier Ideen (Grafisch Sekunden zählen und Frameaufteilung) Java Basics - Anfänger-Themen 18
K Technische Realisierung eines Interface Java Basics - Anfänger-Themen 3
D Brauche mehr Flexibilität bei der Realisierung und weiss nicht wie ich das mache. Java Basics - Anfänger-Themen 10
D Kombinationsfeld => Realisierung im Listener? Java Basics - Anfänger-Themen 2
I [Java Applet] - Realisierung Webprojekt Java Basics - Anfänger-Themen 5
B Tipps für die realisierung eines Projekts: Java Basics - Anfänger-Themen 5
H Generics machen mich verrückt Java Basics - Anfänger-Themen 8
MarvinsDepression Datentypen Generics: Erste Berührungen Java Basics - Anfänger-Themen 6
M Generics Vererbung Listen Java Basics - Anfänger-Themen 2
Cassy3 Generics - CompareTo Java Basics - Anfänger-Themen 21
T Collections Sind Subklassen-Objekte in Listen mit Generics erlaubt? Java Basics - Anfänger-Themen 16
districon Generics implementieren Java Basics - Anfänger-Themen 2
CptK Überprüfen ob übergebenes Objekt zu Generics passt Java Basics - Anfänger-Themen 2
CptK Generics: Klassen die Interface implementieren, aber selbst nicht das Interface sind Java Basics - Anfänger-Themen 8
B Hilfe bei Generics Java Basics - Anfänger-Themen 11
G Generics Compilerfehler Java Basics - Anfänger-Themen 6
G Generics Methoden Java Basics - Anfänger-Themen 7
G Generics Java Basics - Anfänger-Themen 3
L Generics Tripel Java Basics - Anfänger-Themen 26
W Fragen zu Generics Java Basics - Anfänger-Themen 14
S Hilfe. Generics und BiFunctions Java Basics - Anfänger-Themen 10
X Wie Generics richtig benutzen ? Java Basics - Anfänger-Themen 5
S Allgemeine Frage über Generics und Vererbungen Java Basics - Anfänger-Themen 5
S Generics-Problem: Class, Class<?>, Class<Object> Java Basics - Anfänger-Themen 4
I Java Generics factory method Java Basics - Anfänger-Themen 2
M Verständnisfrage zu Generics Java Basics - Anfänger-Themen 7
I Generics und Comparable Java Basics - Anfänger-Themen 14
G Generics mit ? und Diamantoperator Java Basics - Anfänger-Themen 4
G Generics: Wildcard ? Java Basics - Anfänger-Themen 12
D Generics methode Java Basics - Anfänger-Themen 2
I Frage zu Generics und Wildcards Java Basics - Anfänger-Themen 2
N Generics und Casting eines Objekts Java Basics - Anfänger-Themen 1
A Generics Java Basics - Anfänger-Themen 6
A Vererbung/Interfaces/Generics Java Basics - Anfänger-Themen 12
W Generics - Typ zurückbekommen Java Basics - Anfänger-Themen 4
Dimax Erste Schritte Generics von Profis leicht erklärt Java Basics - Anfänger-Themen 7
C Warum funktioniert 'instanceof' bei generics nicht? Java Basics - Anfänger-Themen 4
J Collections Generics: Typ wird nicht erkannt Java Basics - Anfänger-Themen 7
D Generics ArrayList: Bug im Quellcode Java Basics - Anfänger-Themen 14
C Generics Java Basics - Anfänger-Themen 8
M Generics getter und setter Methoden Java Basics - Anfänger-Themen 4
T Generics in Java... Java Basics - Anfänger-Themen 9
J Generics Java Basics - Anfänger-Themen 3
J Generics Datentypen vergleichen Java Basics - Anfänger-Themen 16
V Generics / eigene Liste Java Basics - Anfänger-Themen 4
O Generics - Implementierung Java Basics - Anfänger-Themen 7
Shizmo Frage zu Generics Java Basics - Anfänger-Themen 3
F Multiple Generics Java Basics - Anfänger-Themen 10
G Datentypen verschiedene Objekte in eine ArrayList, Generics Java Basics - Anfänger-Themen 2
H Typsicherheit/Generics Java Basics - Anfänger-Themen 1
U Java generics funktioniert nicht Java Basics - Anfänger-Themen 0
Tarrew Generics: Erste gemeinse Oberklasse als Rückgabewert Java Basics - Anfänger-Themen 1
N Generics Vererbung Wildcard Interface Java Basics - Anfänger-Themen 8
S Generics und Comparable Interface Java Basics - Anfänger-Themen 5
A Generics Java Basics - Anfänger-Themen 4
M Frage zu Generics in Klassen, Abstrakten Klassen und Interfaces Java Basics - Anfänger-Themen 5
R Compiler-Fehler Generics Problem Java Basics - Anfänger-Themen 2
K Interface Generics, Interfaces und Listen - ich bin verwirrt. Java Basics - Anfänger-Themen 7
K Generics bei Klassen- und Interfacedeklarationen Java Basics - Anfänger-Themen 3
D toArray und Generics Java Basics - Anfänger-Themen 2
D Zwei Generics beim Überladen von Methoden Java Basics - Anfänger-Themen 3
C Erste Schritte Filter für Generics oder ähnliches Java Basics - Anfänger-Themen 2
M Frage zu Generics-Deklaration Java Basics - Anfänger-Themen 5
S Frage zu Collection-Generics in Subklassen Java Basics - Anfänger-Themen 6
J Java Generics - Frage zu Types Java Basics - Anfänger-Themen 2
M <T> Generics Java Basics - Anfänger-Themen 7
B Interface Generics: prüfen ob Interface deklariert wird Java Basics - Anfänger-Themen 18
T Polymorphie Generics-Problem Java Basics - Anfänger-Themen 2
B Hilfe beim Verständnis zu Generics Java Basics - Anfänger-Themen 7
J Array Generics Java Basics - Anfänger-Themen 3
J Generics casten Java Basics - Anfänger-Themen 14
J Generics wildcard Java Basics - Anfänger-Themen 6
E Listen und Generics Java Basics - Anfänger-Themen 9
X Generics Java Basics - Anfänger-Themen 6
M Datei einlesen mit generics? Java Basics - Anfänger-Themen 9
D Warum sind Generics mit Vorsicht zu genießen? Java Basics - Anfänger-Themen 6
M OOP Mit Generics auf Methoden zugreifen? Java Basics - Anfänger-Themen 10
S Generics Java Basics - Anfänger-Themen 4
G Generics kein Zugriff auf getter eines Objekts Java Basics - Anfänger-Themen 4
L Datentypen Problem mit Generics und null Java Basics - Anfänger-Themen 6
E Klassen java.util.ArrayList<E> als Generics Java Basics - Anfänger-Themen 16
W Interface Problem mit Generics Java Basics - Anfänger-Themen 2
M OOP Generics und Wildcards Java Basics - Anfänger-Themen 3
D Generics - Warnmeldungen Java Basics - Anfänger-Themen 2
M Polymorphie generics einsteigerprobleme Java Basics - Anfänger-Themen 3
D Vererbung Generics und Vererbung Java Basics - Anfänger-Themen 8
C Generics Array Java Basics - Anfänger-Themen 43
D Fehler mit generics Java Basics - Anfänger-Themen 10
S Generics - CaseInsensitiveMap selber schreiben? Java Basics - Anfänger-Themen 5
K Datentypen Generics Java Basics - Anfänger-Themen 3
P Comparable und Generics Java Basics - Anfänger-Themen 6
I Generics (Subtypen) Java Basics - Anfänger-Themen 17
N Typeinschränkung bei Generics Java Basics - Anfänger-Themen 13
C Generics und Cast Java Basics - Anfänger-Themen 5
H Generics werden in -source 1.2 nicht unterstützt Java Basics - Anfänger-Themen 16
M Datentypen Generics: Exacten Typ ermitteln Java Basics - Anfänger-Themen 6
N Generics und Interfaces Java Basics - Anfänger-Themen 5
S Generics und "generische Feldzuweisungen" Java Basics - Anfänger-Themen 5
lumo Java Generics Java Basics - Anfänger-Themen 19
M verlinkte Liste mit generics Java Basics - Anfänger-Themen 7

Ähnliche Java Themen

Neue Themen


Oben