Terminator Terminator - 3 months ago 17
Java Question

Is it possible to use parametrize generic inner classes?

package generics;
public class InnerClassGenerics{
class Innerclasss{

}
public static void main(String[] args) {
InnerClassGenerics icg=new InnerClassGenerics();
Innerclasss innerclass=icg.new Innerclasss();
}
}


Above code is possible and compiles fine!!!




Why is the below code doesn't compile, and is it possible to parametrize inner classes?

package generics;
public class InnerClassGenerics<T>{
class Innerclasss<T>{

}
public static void main(String[] args) {
InnerClassGenerics<String> icg=new InnerClassGenerics<>();
Innerclasss<String> innerclass=new Innerclasss<>();
}
}


In the above code if the class is made as static it works fine!!!
Why is it not possible without static keyword?

Answer

Normally if there wouldn't be any generic type on outer class you could write code like this:

Outer outer = new Outer();
Inner inner = outer.new Inner();

because each method in inner class already knows what types should it be using.

But situations is little more complicated when outer class uses generic types. Since inner class have access to all members of its outer class (or classes), it also needs to know about generic type used in outer class(es) to ensure type safety while manipulating generic values.

Take a look at this code:

class Outer<T> {
    private T someValue;

    class Inner {
        T getOuterValue(){
            return someValue;
        }
        void setOuterValue(T value){
            someValue=value;
        }
    }
    //rest of code
}

This means that instance of Inner class also depends on generic type from its outer class(es). That is why while creating reference to inner class you need to explicitly use outer class with generic type by writing it as

Outer<String> outer = new Outer<>();
Outer<String>.Inner inner = outer.new Inner();
^^^^^^^^^^^^^

or explicitly say that outer class uses raw type (which is discouraged) like

Outer.Inner inner = outer.new Inner();

If you don't do this, compiler will not know what type to use with generic methods of inner class which are based on generic type of outer class.


So to make your code work you need to:

  1. add outer class type (preferably with its generic type)

  2. invoke constructor of inner class on instance of outer class (just like non-static methods can't be invoked without instance of class, non-static instances of inner classes can't exist without its outer classes)

    InnerClassGenerics<String>.Innerclasss<String> innerclass = icg.new Innerclasss<>();
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^                                 ^^^^
             point 1                                           point 2
    

Oh and one last thing. You shouldn't give same names to generic types in nested classes and its outer classes, like in your case

public class InnerClassGenerics<T>{
    class Innerclasss<T>{
        ...
    }
}

because T from Innerclasss hides T from its outer class InnerClassGenerics (not that it causes current problem, but it can make your life difficult later).