Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding inner generic classes

Tags:

java

generics

I wrote the following code:

public class Test<T> {

    public void method(){
        B b = new B();
    }

    public class B{ }
}

//Some method in some class contains the following lines    
Test<Integer> t = null;
Test.B b = t.new B(); //warning Test.B is a raw type

Why did I get this warning? The declation of the inner type B doesn't contain type parameter, therefore it's not a generic type. Moreover, the specification gives us the following:

A class is generic if it declares one or more type variables

The class B doesn't declare the type variables. So why is it a generic type?

like image 620
St.Antario Avatar asked Jun 30 '15 19:06

St.Antario


4 Answers

Although the inner class B does not declare any type variables, an instance of it implicitly references an instance of the outer class, which does.

Why did I get this warning?

Test<Integer> t = null;
Test.B b = t.new B(); //warning Test.B is a raw type

Because you declared the variable b with a raw type. Instead, you could declare:

Test<Integer>.B b = t.new B(); // no warning!
like image 64
Andy Thomas Avatar answered Oct 01 '22 23:10

Andy Thomas


I agree that the specification of generic classes does not clearly cover your scenario. But the specification of raw types does:

More precisely, a raw type is defined to be one of:

  • The reference type that is formed by taking the name of a generic type declaration without an accompanying type argument list.

  • An array type whose element type is a raw type.

  • A non-static member type of a raw type R that is not inherited from a superclass or superinterface of R.

like image 35
M A Avatar answered Oct 02 '22 00:10

M A


You do not really use the generic type. I will explain it on a slightly more elaborate example:

public class Test<T> {  
    public B method(T t) {
        B b = new B(t);
        return (b);
    }

    public class B {
        T value;

        public B(T value) {
            this.value = value;
        }
    }
}

Here you can see clearly, that B depends on the generic parameter T, without being generic itself. As explained by Andy Thomas, an instance of B can only be created in co-existence with an instance of Test. Therefore, B is (indirectly) generic. In your given example:

Test<Integer> t = null;
Test.B b = t.new B(); //warning Test.B is a raw type

b does not specify a generic parameter, but t does. This is, why you get the warning.

The proper way to write this code would be:

Test<Integer> t = null;
Test<Integer>.B b = t.new B();

With this, B is fully specified and the types match.

like image 27
Turing85 Avatar answered Oct 02 '22 01:10

Turing85


Although B is not parameterized, Test.B b = t.new B(); contains a raw reference to Test, which is parameterized. I got the warning to disappear when I changed the warning line to Test<Integer>.B b = t.new B();

like image 24
swingMan Avatar answered Oct 02 '22 01:10

swingMan