1

Suppose below class (without any errors or even warnings):

class C<T> {
    C(C1<T> c1) { /*...*/ }

    class C1<U> { /*...*/ }
}

Now, how can I make a new instance of it?

new C<String>(new C1<String>()) {};  // Error behind `<String>`: Type arguments given on a raw type 
                                     // + Warning behind `new C1<String>()`: Unchecked assignment: 'com.example.package.C.C1<java.lang.String>' to 'com.example.package.C<java.lang.String>.C1<java.lang.String>'type

new C<String>(new C1<>()) {};        // Error behind `<>`: Type arguments given on a raw type

new C<String>(new C1()) {};          // Warning behind `new C1()`: Unchecked assignment: 'com.example.package.C.C1' to 'com.example.package.C<java.lang.String>.C1<java.lang.String>'

Although the third way doesn't include an error, that isn't what I want! I want new C1<String>. Also, it includes a warning.


Note that the problem is only when C1 is an inner class (not static) of C. For example, there is no problem with below code:

class C<T> {
    C(C2<T> c1) { /*...*/ }

    //class C1<U> { /*...*/ }
}

class C2<V> { /*...*/ }

...

new C<String>(new C2<String>()) {};  // OK
new C<String>(new C2<>()) {};        // OK (and is equivalent)
Mir-Ismaili
  • 13,974
  • 8
  • 82
  • 100

2 Answers2

1

You already nailed it.

When you have an inner class that is not static then you always need an instance of the outer, enclosing class in order to create an inner class object (see here for example).

In that sense, you have a chicken/egg problem here, that simply can't be solved. You need an instance of the inner class to create an outer object, but you would first need that outer object to create an inner object.

And even if there would be some dirty hack to work around this, that would most likely be a dirty hack. Simply don't do that. So the real answer here is to step back and have a closer look at the problem that you actually want to solve using this design. To then find a solution that isn't by broken by design.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • I can understand chicken/egg problem. But: 1) I don't believe it's logically impossible. It's possible if Java wants and will not be dirty. Because it's a compile-time type system and completely under Java's control. 2) **Why does Java let to design such `class` that we can't instantiate it?** – Mir-Ismaili May 25 '18 at 20:29
  • @Mir-Ismaili Java is just a language. Java doesn't *want* anything. **You** are the one who wants something here. And the compiler is telling you "that is not possible"; but you keep insisting "but I want that". You are also wrong about "compile time only". At **runtime**, each instance of an inner class keeps a **reference** to the enclosing outer object. You cant create that inner object without that reference. And the compiler knows that, and does not allow you put down your **illegal** code. And please note: Java does not let you write down this class. As said: – GhostCat May 26 '18 at 04:22
  • the compiler already figures that your idea is **not valid** Java code. Your whole premise is flawed. So, honestly, accept one of the answers, maybe show your appreciation by upvoting ... and then move on to think about the underlying problem, to solve your real problem (see https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem ) – GhostCat May 26 '18 at 04:24
0

As @GhostCat explained, you can never instatiate a non-static inner without providing an instance of the outer. And the type T scope is visible to inner class, you don't need to define another type U. I would write it this way:

    public class Solve {
       public static void main(String[] args){
            C<String> c = new C<>();
            c.c1 = c.new C1();
            c.c1.value = "Inner Generic Class";
            System.out.println(c.c1.value);
       }
    }


    class C<T> {   

       public C1 c1;

       class C1 {
            public T value;
       }
    }
Amith Kumar
  • 4,400
  • 1
  • 21
  • 28