Es ist mal wieder so weit: Type Erasure umgehen!



  • Jawohl, richtig gelesen! Ich würde gerne etwas eigentlich selbst verständliches tun, und zwar einen Array von einem generischen Typen erzeugen. In jeder Sprache, die sowas irgendwie kann, war es trivial. Nicht so in Java.

    Wie bekomme ich in einer Klasse mit Typ-Argument T die Klasse (=Class) von T? Es sind ausdrücklich alle Mittel erlaubt, einschliesslich Reflection. Ich habe viele Beispiele gesehen im Internet, jedoch funktioniert keines, weil man scheinbar mit jeder Implementierung der JVM verschiedene Exceptions an den Kopf geworfen bekommt.

    Sowas muss doch möglich sein?

    $EDIT: Ich habe für meine konkrete Problemstellung einen Workaround gefunden, jedoch bleibe ich bei meiner Frage. Sowas muss möglich sein!

    MfG



  • Eine kniffelige Angelegenheit! Ein erster naiver Ansatz wäre, ein Feld mitzuschleppen, in dem der Typ gespeichert wird.

    public class TypeRefl {
    
    	static class MyGeneric<T> {
    
    		private Class<T> tType;
    
    		public MyGeneric(Class<T> cl) {
    			this.tType = cl;
    		}
    
    		public Class<T> getMyType() {
    			return tType;
    		}
    	}
    
    	public static void main(String[] args) {
    		MyGeneric<Integer> ci = new MyGeneric<Integer>(Integer.class);
    		MyGeneric<Object> co = new MyGeneric<Object>(Object.class);
    
    		System.out.println(ci.getMyType().getName());
    		System.out.println(co.getMyType().getName());
    	}
    }
    

    Eindeutiger Nachteil ist dabei eben, dass das Feld mitgeschleppt werden und die entsprechende Klasse im Konstruktor mitgegeben werden muss. Wenigstens ist das Ganze einigermaßen sicher, denn sowas funktioniert nicht:

    new MyGeneric<Boolean>(Integer.class) // nicht korrekt
    

    Selbst entlang der Vererbungshierarchie ist es verboten, etwas anderes als die Klasse von T dem Konstruktor zu übergeben:

    new MyGeneric<Number>(Integer.class); // nicht korrekt
    


  • Java ist im Prinzip ein Haufen sinnloser Einschränkungen. Damit muss man leben, wenn man es unbedingt verwenden will. 🤡



  • 314159265358979 schrieb:

    Java ist im Prinzip ein Haufen sinnloser Einschränkungen. Damit muss man leben, wenn man es unbedingt verwenden will. 🤡

    Und was hast du zum Thema beizutragen?



  • 314159265358979 schrieb:

    Java ist im Prinzip ein Haufen sinnloser Einschränkungen. Damit muss man leben, wenn man es unbedingt verwenden will. 🤡

    Sinnlos ist das nicht, es geht hauptsächlich um die Rückwärtskompatibilität des Bytecodes.



  • /rant/ schrieb:

    Jawohl, richtig gelesen! Ich würde gerne etwas eigentlich selbst verständliches tun, und zwar einen Array von einem generischen Typen erzeugen. In jeder Sprache, die sowas irgendwie kann, war es trivial. Nicht so in Java.

    T[] meinArray = (T[]) new Object[n];

    Wie bekomme ich in einer Klasse mit Typ-Argument T die Klasse (=Class) von T?

    am besten gar nicht. Ist das eine andere Aufgabe oder hat noch was mit Frage 1 zu tun?

    Es sind ausdrücklich alle Mittel erlaubt

    Das beste Mittel wäre einfach dein Design zu überdenken wenn du in so ein Problem rennst 😕



  • gastantwort schrieb:

    T[] meinArray = (T[]) new Object[n];

    Na dann wappne dich mal für die ClassCastExceptions zur Laufzeit.

    gastantwort schrieb:

    Das beste Mittel wäre einfach dein Design zu überdenken wenn du in so ein Problem rennst 😕

    Möglich. Vielleicht könnten wir eine bessere Lösung finden, wenn /rant/ uns noch mehr Informationen gibt.



  • _kermit schrieb:

    gastantwort schrieb:

    T[] meinArray = (T[]) new Object[n];

    Na dann wappne dich mal für die ClassCastExceptions zur Laufzeit.

    Nö, wieso 😕



  • gastantwort schrieb:

    _kermit schrieb:

    gastantwort schrieb:

    T[] meinArray = (T[]) new Object[n];

    Na dann wappne dich mal für die ClassCastExceptions zur Laufzeit.

    Nö, wieso 😕

    Das habe ich bereits so getestet. Für T = String kann ich zwar etwas rein schreiben in den Array, beim Auslesen bekomme ich aber eine Exception. Keine Chance also.

    Ich habe einfach eine Liste von T, aus welcher ich eine bestimmte Anzahl von Elementen in einen Array abfüllen will.

    314159265358979 schrieb:

    Java ist im Prinzip ein Haufen sinnloser Einschränkungen. Damit muss man leben, wenn man es unbedingt verwenden will. 🤡

    Leider muss man auch damit leben, wenn man es verwenden muss 🤡



  • /rant/ schrieb:

    gastantwort schrieb:

    _kermit schrieb:

    gastantwort schrieb:

    T[] meinArray = (T[]) new Object[n];

    Na dann wappne dich mal für die ClassCastExceptions zur Laufzeit.

    Nö, wieso 😕

    Das habe ich bereits so getestet. Für T = String kann ich zwar etwas rein schreiben in den Array, beim Auslesen bekomme ich aber eine Exception. Keine Chance also.

    hä?

    public class Test<T> {
    
    	private T[] arr;
    
    	Test() {
    		this.arr = (T[]) new Object[12];
    	}
    
    	void set(int i, T t) {
    		this.arr[i] = t;
    	}
    
    	T get(int i) {
    		return this.arr[i];
    	}
    
    	public static void main(String[] args) {
    		Test<String> x = new Test<String>();
    		x.set(0, "ololol");
    		String test = x.get(0);
    		System.out.println(test);
    	}
    }
    


  • Ich brauche den Array, nicht ein einzelnes Element. Gib mal den gesamten Array zurück und versuche, auf ein Element zuzugreifen. Siehe da, eine ClassCastException 🙂



  • /rant/ schrieb:

    Ich brauche den Array, nicht ein einzelnes Element. Gib mal den gesamten Array zurück und versuche, auf ein Element zuzugreifen. Siehe da, eine ClassCastException 🙂

    Quatsch, wieso sollte es einen Unterschied machen ob ich in "get" auf das arrray zugreife oder woanders? Du kriegst nur eine exception, wenn du versuchst es in ein String array zu casten, was es ja offensichtlich nicht ist, sondern ein Object array.



  • Eben, aber ich brauche einen String-Array, wenn T für String stehen muss. Darum ist "Quatsch" keine hilfreiche Antwort. Die Exceptions kommen früher oder später.



  • /rant/ schrieb:

    Eben, aber ich brauche einen String-Array

    Dann ist dein Programm eben nicht generisch und ein Grund dein Design zu überdenken.



  • gastantwort schrieb:

    /rant/ schrieb:

    Eben, aber ich brauche einen String-Array

    Dann ist dein Programm eben nicht generisch und ein Grund dein Design zu überdenken.

    Offensichtlich. rant, du hast also eine Liste, in denen Ts drinstehen. Diese möchtest du in einen T-Array packen. Beispielsweise so:

    List<T> values = new ArrayList<T>();
    List<T> filteredValues = new ArrayList<T>();
    
    for(T t : values) {
    	if(/* Dein Kriterium */) {
    		filteredValues.add(t);
    	}
    }
    
    T[] arr = new T[filteredValues.size()];
    filteredValues.toArray(arr);
    

    Oder spricht etwas dagegen?



  • _kermit schrieb:

    Oder spricht etwas dagegen?

    Ja, dass man keine generischen Arrays anlegen kann. Aber das ändert nichts an der Sache dass offenbar irgendwo im Design etwas faul ist, aber dazu haben wir zu wenige Informationen.



  • gastantwort schrieb:

    _kermit schrieb:

    Oder spricht etwas dagegen?

    Ja, dass man keine generischen Arrays anlegen kann. Aber das ändert nichts an der Sache dass offenbar irgendwo im Design etwas faul ist, aber dazu haben wir zu wenige Informationen.

    Stimmt, innerhalb einer Klasse<T> wäre das so nicht möglich.

    Beim Fehler im Design stimme ich dir zu. Warten wir mal Zusatzinfos ab 😉



  • Gibt es irgendeinen Grund keine generischen Klassen aus dem Collection-Framework zu verwenden? Falls du bei irgendeiner API ein Array übergeben musst, dann benutze doch ArrayList und die Methode toArray().

    L. G.
    Steffo



  • List.toArray liefert aber auch nur dann ein T[] zurück, wenn man ein vorkonstruiertes T[] übergibt - selbes Problem.


Anmelden zum Antworten