Generics - Type erasure

Tarrew

Top Contributor
Hey, ich habe grade ein bisschen Probleme bei der Typersetzung des Compilers bezüglich Java Generics.
Ich habe beispielsweise folgende Klassen:
Java:
public class Foo implements Comparable<Foo>{
int wert;

public Foo(int x) {
	wert=x;
}
	@Override
	public int compareTo(Foo o) {
		return wert-o.wert;
	}
	
	public static <E extends Comparable<? super E>> E[] bubbleSort(E[] array) {
        for(int iter =1; iter< array.length; iter++){
            for(int inner = 0; inner < (array.length - iter); inner ++){
                if((((array[inner])).compareTo(array[inner+1])) > 0){
                    E tmp = array[inner];
                    array[inner] = array[inner + 1];
                    array[inner + 1] = tmp;
                }                
            }
        }
        return array;
    }

}
und
Java:
public class Bar extends Foo {

	public Bar(int x) {
		super(x);
	}

}

Jetzt kann ich (trivialerweise) folgenden Aufruf machen:
Java:
      Foo[] fooArray = new Foo[10];
		for(int i=0; i<10; i++){
			fooArray[i]=new Foo(random.nextInt(50));
		}
		Foo[] fooArray2 = Foo.bubbleSort(fooArray);

(Ich weiß, das Originalarray wird schon geändert, ich returne nur nochmal das Array und speicher es erneut in einer anderen Variable um mein Problem mit den Rückgabewerten zu veranschaulichen).

Folgender Aufruf schlägt (auch trivialerweise) fehl:
Java:
                Bar[] barArray = new Bar[10];
		for(int i=0; i<10; i++){
			barArray[i]=new Bar(random.nextInt(50));
		}
	
		Bar[] barArray2 = Foo.bubbleSort(barArray);
Das kann ja nicht gehen, weil Bar nicht Comparable<Bar> implementiert und deswegen der generische Typ "E" nicht auf Bar gesetzt werden kann weil sonst die Methodensignatur nicht mehr passt.

Jetzt ist es aber so, dass folgende Zeile klappt:
Java:
Foo[] fooArray2 = Foo.bubbleSort(barArray);
Mit dem barArray genau wie im vorigen Beispiel erzeugt.

Wie kann man sich das vorstellen. Der Compiler versucht erst, den generischen Typen auf "Bar" zu setzen und merkt, dass das nicht funktioniert. Dann probiert ers mit der Oberklasse "Foo" und merkt das passt oder wie läuft das?

Ich hatte die Frage schonmal woanders gestellt, da ging die letzte Zeile nicht durch und es kam ein "Bound mismatch". Ist das irgendein "Feature" aus einer neuen Java-Version oder so?

Hoffe mir kann jemand erklären, was da genau passiert, wie dieser generische Typ ersetzt wird.
Ich hab ja meine Vermutung geäußert bin allerdings verwirrt, dass es bei jemand anderem nicht kompiliert hat.

Grüße
 
Zuletzt bearbeitet:

CSHW89

Bekanntes Mitglied
Folgender Aufruf schlägt (auch trivialerweise) fehl:
Java:
                Bar[] barArray = new Bar[10];
		for(int i=0; i<10; i++){
			barArray[i]=new Bar(random.nextInt(50));
		}
	
		Bar[] barArray2 = Foo.bubbleSort(barArray);
Das kann ja nicht gehen, weil Bar nicht Comparable<Bar> implementiert und deswegen der generische Typ "E" nicht auf Bar gesetzt werden kann weil sonst die Methodensignatur nicht mehr passt.
Warum sollte das fehlschlagen? Hast du es getestet? Bei mir funktioniert das sowohl mit Java 7 als auch mit 8. Die Sache ist, wenn E = Bar ist, muss E nicht Comparable<Bar> implementieren, sondern Comparable<? super Bar>. Und das tut es, denn Bar implementiert Comparable<Foo> und Foo ist eine Superklasse von Bar.
Ob die compareTo-Funktion von Foo noch korrekt mit Bar-Objekten arbeitet, oder sie doch von Bar überschrieben werden sollte, ist eine andere Frage, aber nicht die des Compilers ;).

lg Kevin
 
Zuletzt bearbeitet:

Tarrew

Top Contributor
Ach Mist, danke das du mich drauf hinweist.

Das war schon mein "korrigierter Code", in echt sollte da stehen ..."extends Comparable<E>.
Kann den Beitrag leider nicht mehr editieren.

Also die Klasse Foo sieht so aus:
Java:
public class Foo implements Comparable<Foo>{
int wert;
 
public Foo(int x) {
	wert=x;
}
	@Override
	public int compareTo(Foo o) {
		return wert-o.wert;
	}
 
	public static <E extends Comparable<E>> E[] bubbleSort(E[] array) {
        for(int iter =1; iter< array.length; iter++){
            for(int inner = 0; inner < (array.length - iter); inner ++){
                if((((array[inner])).compareTo(array[inner+1])) > 0){
                    E tmp = array[inner];
                    array[inner] = array[inner + 1];
                    array[inner + 1] = tmp;
                }                
            }
        }
        return array;
    }
 
}
 
Zuletzt bearbeitet:

CSHW89

Bekanntes Mitglied
Ah ja das ist wirklich interessant. Die Variante "Bar[] barArray2 = Foo.bubbleSort(barArray);" gibt bei Java 7 und 8 einen Fehler, allerdings aus unterschiedlichem Grund. Und die Variante "Foo[] fooArray2 = Foo.bubbleSort(barArray);" gibt nur bei Java 7 einen Fehler.

Ok, ich denke Java 7 sagt sich hier "Bar[] barArray2 = Foo.bubbleSort(barArray);" das Argument ist vom Typ Bar[], also muss E = Bar. Danach merkt der Compiler, dass das Argument nicht die notwendige Eigenschaft hat, und gibt ein "Bound mismatch" aus.

Java 8 ist da wohl etwas intelligenter und sagt sich, das Argument ist vom Typ Bar[], also muss E = Bar oder irgendeine Superklasse davon sein, denn das Argument würde ja auch darein passen. Dabei merkt der Compiler dann, dass Bar nicht passt, ein Supertyp, nämlich Foo aber sehr wohl. Also setzt er E = Foo und der Rückgabetyp ist Foo[]. Deshalb quitiert er die erste Variante dann mit einem "Type mismatch: cannot convert from Foo[] to Bar[]", und lässt die zweite Variante durch.

Ich hatte vor kurzen mal etwas dazu gelesen, dass auf Grund der Lambdas in Java 8 der Compiler etwas intelligenter bei der Type inference agiert. Hier macht sich das dann auch bemerkbar.

lg Kevin
 

Tarrew

Top Contributor
Hey, ich melde mich nochmal. Erstmal Danke für die Erläuterung. Das macht für mich auch erstmal Sinn.

Hab dann grad durch Zufall was festgestellt:
Ich habe eine generische Klasse "Tier":
Java:
public abstract class Tier<T extends Tier<T>> {

}

Dann noch eine Klasse Katze:
Java:
public class Katze extends Tier<Katze> {

}
und dazu noch eine Klasse Hauskatze, die einfach nur eine Unterklasse von Katze ist.

Zu guter Letzt die Klasse Käfig:
Java:
package main;

public class Käfig<T extends Tier<T>> {

	T inhalt;

	public void add(T tier) {
		inhalt = tier;
	}
	
	public <E extends Tier<E>>void add2(E tier){
		E lokalerInhalt;
		lokalerInhalt = tier;
	}

	public T remove() {
		T result = inhalt;
		inhalt = null;
		return result;
	}
	

	public static void main(String[] args) {
		Käfig<Katze> k = new Käfig<Katze>();
		k.add(new Katze());
		k.add(new Hauskatze()); 
		k.add2(new Hauskatze());		
	}
	
}

So, das komische ist unter Java7 schlägt der k2.add Aufruf natürlich fehl, wie schon erläutert wurde.
Das Komische ist, dass "k.add(new Hauskatze()); " auch unter Java7 schon funktioniert.

Im Prinzip ist es ja genau das gleiche. Nur das einmal der generische Parameter T auf Klassenebene "erzeugt" wird und einmal auf Methodeneben (falls man das so sagen kann).

Jedenfalls sollten T und E genau die gleichen Klassen 'einschränken'.
Wie kommt es, dass der k.add(new Hauskatze()); geht und der k.add2(new Hauskatze()); fehlschlägt.

Anscheinend war Java7 ja schon schlau genug zu merken, dass Hauskatze auch als Parameter akzeptiert wird, obwohl der Parameter "T" ist, und T ja das Interface "direkt" implementiert.

Sobald man das gleiche macht mit einem generischen Parameter in einer Methode wird eine Hauskatze nicht akzeptiert. Vllt hat da jemand eine Erklärung zu.

Danke
 

CSHW89

Bekanntes Mitglied
Du erstellst einen Käfig mit T=Katze. Somit ist die Signatur von add auf jeden Fall schon vorgegeben: "add(Katze tier)". Und da eine Hauskatze auch eine Katze ist, funktionierts. add2 funktioniert mit Hauskatze ja deshalb nicht, weil Java selbst das E bestimmen muss, und es fälschlicherweise auf Hauskatze setzt.

lg Kevin
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
S Type safety Warnings beim casten von Generics Allgemeine Java-Themen 6
G Generics in Map. Type of value abhängig vom key Allgemeine Java-Themen 3
T Generics, Enumerations und Type-Casts Allgemeine Java-Themen 13
J Best Practice Generics mit Enum Allgemeine Java-Themen 3
H Kombination Interface und Abstrakte Klasse bei Generics Allgemeine Java-Themen 3
Zeppi Cast Object in Generics Allgemeine Java-Themen 4
P Generics und Arrays Allgemeine Java-Themen 6
M Generics / Typen Allgemeine Java-Themen 1
Kirby.exe InsertionSort mit Generics Allgemeine Java-Themen 33
Kirby.exe Vererbung bei Generics Allgemeine Java-Themen 7
H Klarnamen etc... (von Wie Generics lernen?) Allgemeine Java-Themen 26
D Wie Generics lernen? Allgemeine Java-Themen 26
L Compiler-Fehler Generics beim Anhängen von Predicates Allgemeine Java-Themen 1
W Vererbung Generics - mal wieder die verhaßte Rückwärtskompatibilität Allgemeine Java-Themen 2
S Verstaendnisfrage Generics Allgemeine Java-Themen 19
W Generics + Vererbung Allgemeine Java-Themen 47
I Methoden Generics-Methode Allgemeine Java-Themen 3
D Mit Generics arbeiten - Übungsaufgabe Allgemeine Java-Themen 3
K Factory Pattern: Mit Generics umgehen Allgemeine Java-Themen 6
G Generics Allgemeine Java-Themen 31
perlenfischer1984 Liste mit generics zurück liefern Allgemeine Java-Themen 8
Hacer Generics & Collections Allgemeine Java-Themen 8
Neumi5694 Interface Generics für Enum-Filterung verwenden Allgemeine Java-Themen 5
H Collector Generics Problem (incl. Stream & Lambda) Allgemeine Java-Themen 4
C Gemeinsame Oberklasse zweier Generics Allgemeine Java-Themen 10
erdmann Datentypen Methodendeklaration mit Generics Allgemeine Java-Themen 2
Z Datentypen Verschachtelte Generics Allgemeine Java-Themen 1
Neumi5694 Datentypen Generics Allgemeine Java-Themen 5
S Mit Generics Klasse erstellen die selbst T erweitert..? Allgemeine Java-Themen 4
N Problem mit Generics und Interface Allgemeine Java-Themen 4
H Generics als Parameter Allgemeine Java-Themen 1
kaoZ Generics und Vererbung Allgemeine Java-Themen 3
A Datentypen Generics: Wie am besten auf Typparameter zugreifen Allgemeine Java-Themen 2
C Generics Objekt in ArrayList Allgemeine Java-Themen 2
vandread Kleine Generics Aufgabe aus einer Prüfung... wie ist das gemeint? Allgemeine Java-Themen 6
G Generics sind zu streng - oder ich zu naiv? Allgemeine Java-Themen 3
G Verschachtelte Generics Allgemeine Java-Themen 2
O Generics Allgemeine Java-Themen 42
M Problem mit Generics Allgemeine Java-Themen 10
M Generics (bounded wildcards statt Interface Bezeichnern) -- Sinn oder Unsinn? Allgemeine Java-Themen 2
darekkay Generics: Wildcard und Object Allgemeine Java-Themen 5
H Collections Generics und Reflection Allgemeine Java-Themen 6
F Google Guice + Generics + Vererbung Allgemeine Java-Themen 5
H Problem mit Java Generics Allgemeine Java-Themen 6
J Generics: Typparameter als Klasse zurückliefern Allgemeine Java-Themen 4
H Generics Allgemeine Java-Themen 5
P Probleme mit Generics Allgemeine Java-Themen 5
B Generics und primitve arrays Allgemeine Java-Themen 6
M Generics Allgemeine Java-Themen 11
1 Collections Generics, internes Verhalten Allgemeine Java-Themen 16
T Warnungsfreie Verwendung von Generics Allgemeine Java-Themen 11
M Probleme mit Generics Allgemeine Java-Themen 5
D Java Generics Allgemeine Java-Themen 8
2 Generics: bounded wildcards Allgemeine Java-Themen 4
J Generics / vermeiden von downcasts Allgemeine Java-Themen 2
2 Generics oder nicht? Allgemeine Java-Themen 8
E Problem mit Generics und Comparable Allgemeine Java-Themen 16
W Erweitern einer Klasse mit Generics Allgemeine Java-Themen 8
H Generics für Methode Allgemeine Java-Themen 14
N Überladen mit Hilfe von Generics Allgemeine Java-Themen 3
S Generics: Fuer Set<T> ein T-Klassenobjekt erhalten? Allgemeine Java-Themen 3
Q Der innere Typ von Generics? Allgemeine Java-Themen 3
N Generics-NullpointerException Allgemeine Java-Themen 7
2 Generics - Typ Allgemeine Java-Themen 12
P Generics Problem Allgemeine Java-Themen 10
N Generics Allgemeine Java-Themen 3
V Frage zu Generics Allgemeine Java-Themen 2
S java generics klassen deklaration Allgemeine Java-Themen 7
B hashtable für unterschiedliche Typen - mit Generics Allgemeine Java-Themen 8
E Generics Allgemeine Java-Themen 3
MQue Generics Allgemeine Java-Themen 4
R Problem mit Reflection und Generics Allgemeine Java-Themen 3
C Klassen, die aufeinander verweisen (mit Generics) Allgemeine Java-Themen 16
G Generics - W.card unter Nutzung von Annotationsklasse? Allgemeine Java-Themen 6
G sortieren von generics Allgemeine Java-Themen 10
A Generics Verständnisfrage Allgemeine Java-Themen 7
Z Generics funzt nicht? Allgemeine Java-Themen 2
T Generics Allgemeine Java-Themen 18
G ComboBox: Nur eine Art Klasse zulassen (Generics) Allgemeine Java-Themen 3
J Generics Expertenwissen? Allgemeine Java-Themen 5
S Generics-Problem Allgemeine Java-Themen 3
T Generics und Wil-dcards Allgemeine Java-Themen 8
Q Typen von Generics & Casten Allgemeine Java-Themen 3
S Generics Allgemeine Java-Themen 2
R Problem mit Generics Allgemeine Java-Themen 2
G Trotz Generics Cast-Fehler! Allgemeine Java-Themen 5
T TreeMap durch Comparator mit Generics sortieren Allgemeine Java-Themen 9
T Generics und instanceof Allgemeine Java-Themen 10
T Generics und Exceptions Allgemeine Java-Themen 6
M Beliebig viele Typen bei Generics Allgemeine Java-Themen 3
G Reflection objekt mit generics erzeugen Allgemeine Java-Themen 5
S Singleton Pattern mit Generics Allgemeine Java-Themen 4
G Generics und Comparable Allgemeine Java-Themen 11
H Generics Problem Allgemeine Java-Themen 3
F Generics: spricht etwas dagegen raw types zu verwenden? Allgemeine Java-Themen 31
M Generics - besser programmieren, Warnung umgehen Allgemeine Java-Themen 4
E Java, UML, Generics Allgemeine Java-Themen 6
P Array von Vectoren + Generics Allgemeine Java-Themen 6
M ArrayList erweitern - generics Allgemeine Java-Themen 4
E Generics -> UML Allgemeine Java-Themen 4

Ähnliche Java Themen

Neue Themen


Oben