1

I have this code

public class OuterClass<T> {
    public OuterClass() {
        InnerClass[] array = new InnerClass[4]; // compile-error
    }

    private class InnerClass {

    }
}

which does not compile because of Cannot create a generic array of OuterClass.InnerClass in the line where I create the array.

Why is this so and how can I fix/workaround it?

AyCe
  • 597
  • 2
  • 8
  • 27
  • I'd love to know how this is a duplicate. The linked question is not directly related to this. I don't want to create a generic array. – AyCe Aug 01 '14 at 20:14
  • AyCe, you're right - it doesn't relate to the duplicate question. I reopened your question accordingly – Konstantin Yovkov Aug 01 '14 at 21:42
  • Possibly this thread would be helpful, too: http://stackoverflow.com/questions/20475142/java-doesnt-allow-arrays-of-inner-classes-for-a-generic-class – Konstantin Yovkov Aug 01 '14 at 22:07

3 Answers3

4

InnerClass is a non-static inner class. Non-static members of OuterClass are within the scope of the type parameter T of OuterClass. This means that InnerClass is implicitly generic.

Every time inside an instance context of OuterClass where you write just InnerClass, without explicitly qualifying it, it is implicitly treated as OuterClass<T>.InnerClass. So when you wrote

InnerClass[] array = new InnerClass[4];

the compiler sees it as

OuterClass<T>.InnerClass[] array = new OuterClass<T>.InnerClass[4];
//                                                ^
// see? you are using "new" to create an array of a parameterized type

Even though the parameter is not physically on InnerClass, it is on the OuterClass, it is still a type parameter of InnerClass, just written in a different position.

Creating an array of a parameterized type, as you may know, is not allowed in Java. Just like how List<T>[] = new List<T>[4]; is not allowed.

So what's the usual workaround for creating an array of a generic type? You can create an array of the raw type:

List<T>[] = new List[4]; // legal

or of the wildcard-parameterized type:

List<T>[] = (List<T>[])new List<?>[4]; // legal

Now back to your problem of the inner class. What is the raw type in this case? It is not InnerClass, because as we have seen, it is implicitly parameterized with T. We have to explicitly qualify InnerClass with a raw OuterClass to get the raw InnerClass:

InnerClass[] = new OuterClass.InnerClass[4]; // legal

Alternately using the wildcard-parameterized type (again, we have to put the wildcard on OuterClass):

InnerClass[] = (InnerClass[])new OuterClass<?>.InnerClass[4]; // legal
newacct
  • 110,405
  • 27
  • 152
  • 217
1

Workaround: Make inner class static

public class OuterClass<T> {
    public OuterClass() {
        InnerClass[] array = new InnerClass[4];
    }

    private static class InnerClass {

    }
}
Mehmet Ataş
  • 9,857
  • 5
  • 42
  • 70
  • beware of statics. They cannot access anything else inside your class. Static classes are instantiated first and their lifetime is the lifetime of the class v. the object. That means that instance variables will not work with your Inner Class – Andrew Scott Evans Aug 01 '14 at 19:39
  • There are many ways to solve this problem. InnerClass can hold an instance of OuterClass and can access non-static members of OuterClass via this instance. – Mehmet Ataş Aug 01 '14 at 19:44
  • just sounds a bit circular/overcomplicated. I didn't mark down or anything because it could work. – Andrew Scott Evans Aug 01 '14 at 19:47
  • I know that making the inner class static would work. Your second idea is exactly my current workaround and seems to work pretty well. However, the other answer has exactly what I was looking for. – AyCe Aug 01 '14 at 20:13
-3

you have a paremetization problem. Generics need to now the Type, what it is dealing with. Integer, Double, Float; etc. at compile time. That type trickles down to your encapsulated classes but not in a way specifying the type (outerclass.innerclass) and that is why there is a problem (see newacct).

Therefore, you need to parametize the InnerClass since it has no idea what is being dealt with. Taking the class out of the outer class works.

However,your fix for an inner class is as so.

 package quicktest;

 public class OJust<T>{
      public OJust() {
         InnerClass[] array = new InnerClass[4]; // compile-error
     }

     private class InnerClass<T>{

     }

}

Andrew Scott Evans
  • 893
  • 11
  • 24