views:

179

answers:

3

Yesterday I attempted to create an array of objects, belonging to a non-static inner class of a generic class. It seems that there is no nice way of doing so.


First attempt:

public class Wibble<T>{  
      public static void main(String...args){  
            new Wibble<String>();  
      }  
      public Wibble(){  
            Bar[] bar = new Bar[11];  
      }  
      static class Foo{}  
      class Bar extends Foo{}  
}

This does not work, because 'Bar' within the context of 'Wibble' is implicitly generic, resulting in the following error:

Exception in thread "main" java.lang.Error:  
Unresolved compilation problem: Cannot create a generic array of Wibble<T>.Bar  

at Wibble.<init>(Wibble.java:7)  
at Wibble.main(Wibble.java:4)


Second attempt:

public class Wibble<T> {  
      public static void main(String...args){  
            new Wibble<String>();  
      }  
      public Wibble(){  
            Bar[] bar = (Bar[])new Foo[11];  
      }  
      static class Foo{}  
      class Bar extends Foo{}  
}

This does not work because arrays can only be cast to a generic type from the most recent known non-generic type. For the generic Bar, the most recently known non-generic type is the non-generic Bar, which cannot (easily?) be referenced within the context of the parent class. Resulting in the following error:

Exception in thread "main" java.lang.ClassCastException:  
[LWibble$Foo; cannot be cast to [LWibble$Bar;  

at Wibble.<init>(Wibble.java:7)  
at Wibble.main(Wibble.java:4)


Final attempt:

public class Wibble<T> {  
      private static final Class<?> BARCLASS = new Wibble<Object> (false).new Bar().getClass();  
      public static void main(String...args){  
           new Wibble<String>();  
      }  
      private Wibble(boolean flag){}
      public Wibble(){  
           Bar[] bar = (Bar[])Array.newInstance(BARCLASS, 11);  
      }  
      static class Foo{}  
      class Bar extends Foo{}  
}

This works, however, if you wish to create the array within the constructor, you also need a (private) dummy constructor, so that you can get the class.
Furthermore if the parent class is abstract, you need to provide dummy implementations for all of the abstract methods.


As I finished writing this up, I realised that

public class Wibble<T> {    
      public static void main(String...args){  
            new Wibble<String>();  
      }  
      private Wibble(boolean flag){}
      public Wibble(){  
            Bar[] bar = (Bar[])Array.newInstance(Bar.class, 11);  
      }  
      static class Foo{}  
      class Bar extends Foo{}  
}

Works as well, and figured I might as well still post. It's still ugly though, and there's no justification for the fact that normal syntax does not work.

+2  A: 

if you declare also Bar as static class, then the following code (i.e. the most obvious) will works both at compile and at runtime:

Bar[] bar = new Bar[11];

EDIT

using java.lang.reflect.Array.newInstance is the preferred way to allocating new generic arrays at runtime

dfa
In my actual code, the non-static inner class contained instances of the parent classes generic type, meaning that Bar could not be static.Regarding your edit, my main issue is the fact that the array is considered generic at all. The runtime type of the array is easily deducable. I don't think that there should be any problems when that is the case.
+1  A: 

If you need to keep the "implicit genericity", i.e. you can't make the class static, you can do Bar[] bar = new Bla.Bar[11];, though you'll get a warning for that.

sepp2k
+1  A: 
List<Bar> bars = new ArrayList<Bar>();

Sorted (er, ordered).

Tom Hawtin - tackline
heh!
Chii