Hat jemand Informationen darüber, ob sich bei den Generics noch was tut?



  • Ich habe soeben etwas unschönes "entdeckt". 😞

    Man kann ein "generisches" Array nur innerhalb des generischen Typs verwenden, außerhalb wird T[] in ein <konkreter Typ>[] gecastet, was aber fehlschlägt, da man eigentlich nicht viel mehr Möglichkeit hat, als intern ein Array vom Typ des Upper-Bounds, meistens Object[], zu erstellen. Man betrachte die beiden markierten Zeilen in main:

    public final class Test<T>
    {
    	public static void main(String[] args)
    	{
    		// *PENG* !!
    		Integer anInteger = 17;
    		new Test<Integer>().run()[10] = anInteger;
    
    		// *PENG* !!
    		String[] array = new Test<String>().run();
    		System.out.println(array);
    	}
    
    	private T[] run()
    	{
    		T[] x = createArray();
    		System.out.println(x);
    		return x;
    	}
    
    	private T[] createArray()
    	{
    		return (T[])(new Object[10]);
    	}
    }
    

    Obwohl die statische Typsicherheit eigentlich vollkommen gewährleistet ist, fliegt eine ClassCastException, da ein Object[] natürlich kein Integer[] ist.
    Für mich stellt sich da die Frage, ob Arrays in Verbindung mit Generics überhaupt noch nutzbar sind? 😞
    Ist eigentlich vorgesehen, dass man an den Generics, die ja sonst sehr weich sind, noch was richtet? Ich habe keinen entsprechenden JSR gefunden, würde das aber sehr bedauern, wenn es so bleiben würde. Überhaupt habe ich noch keine großen Informationen darüber gefunden, was JAva 6.0 bieten wird. Weiß da jemand schon näheres?


  • Mod

    Man kann sich eine Methode wie in folgendem Beispiel schreiben.

    import java.lang.reflect.Array;
    
    public class GenericsTest
    {
       public static void main (String[] args)
       {
          Integer myInt = 10;
          Integer[] integerArray = createArray(myInt.getClass(),5);
          for (int i = 0 ; i < integerArray.length ; ++i)
          {
             integerArray[i] = i;
             System.out.println(integerArray[i]);
          }
       }
    
       public static <T> T[] createArray(final Class<T> type, final int size)
       {
          if (type == null) throw new NullPointerException ("type is null.");
          if (size < 0) throw new IllegalArgumentException ("size is negative.");
          return (T[]) Array.newInstance(type,size);
       }
    }
    

    Man benötigt aber in jedem Fall ein Objekt des Typs oder das passende Class-Objekt. Das Problem ist, dass Generics nur zur Compilezeit existieren, während die Array-Erzeugung zur Laufzeit stattfindet. Da ist der Typ dann nicht mehr bekannt, weshalb das mit Generics so einfach nicht geht. Man muss sich da mit Reflection helfen.

    Leider fliegt hier eine Warnung, gegen die man momentan wohl nichts tun kann: Ich habe gerade festgestellt, dass die @SuppressWarnings-Annotation in Java 5.0 anscheinend noch nicht richtig eingebaut ist.



  • Hallo Gregor,

    dein Code compiliert so nicht:
    [java]import java.lang.reflect.Array;

    class GenericsTest
    {
    public static void main (String[] args)
    {
    Integer myInt = 10;
    Integer[] integerArray = createArray(myInt.getClass(),5);
    for (int i = 0 ; i < integerArray.length ; ++i)
    {
    integerArray[i] = i;
    System.out.println(integerArray[i]);
    }
    }

    public static <T> T[] createArray(final Class<T> type, final int size)
    {
    if (type == null) throw new NullPointerException ("type is null.");
    if (size < 0) throw new IllegalArgumentException ("size is negative.");
    return (T[]) Array.newInstance(type,size);
    }
    }[/java]
    ⚠ Type mismatch: cannot convert from ? extends Object[] to Integer[]
    Auch mit Typparameter vor dem Methodenaufruf <Integer>createArray(myInt.getClass(), 5) mag ers nicht fressen.

    Ich kenn diese Vorgehensweise aber so ähnlich aus dem Java API (dort wird eine Array-Instanz übergeben). Aber das bringt mich zurück zur eigentlichen Frage, nämlich ob Sun irgendwas verlautbaren hat lassen bzgl. der Zukunft der Generics? Ich fürchte, so lange new T[int] nicht geht, wird es immer hässlich und sehr inperformant bleiben...
    Ich finde es halt schade, weil alles andere sonst extrem godlike ist an den Generics.


  • Mod

    Optimizer schrieb:

    dein Code compiliert so nicht:

    Natürlich kompiliert der. Der Fehler liegt bei dir. Welchen Compiler nutzt du?


  • Mod

    Optimizer schrieb:

    Überhaupt habe ich noch keine großen Informationen darüber gefunden, was JAva 6.0 bieten wird. Weiß da jemand schon näheres?

    AFAIK ist da noch nichts oder zumindest nicht viel öffentlich bekannt.



  • Stimmt, javac frisst ihn.
    Ich benutze Eclipse 3.1 M4. Angeblich soll er schon alles können und das Java 1.5 API hab ich auch schon bauen können. Aber ich weiß jetzt natürlich nicht auswendig, ob da irgendwo ne polymorphe Methode vorkommt...



  • Optimizer schrieb:

    ...Eclipse 3.1 M4. Angeblich soll er schon alles können und das Java 1.5...

    Hab ich zuerst auch gedacht, bis ich herausgefunden habe dass dieser Compiler sogar Code kompiliert, den selbst javac zurückweist (nun ja, dieser Code hatte hübsche Nebeneffekte, wie Methoden die nicht überschreibbar waren, weil man als Argument A und nicht A gesetzt hat (Fehlermeldung von Eclipse) 😕 ...).


Anmelden zum Antworten