St.Antario
St.Antario

Reputation: 27385

Understanding inner generic classes

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?

Upvotes: 5

Views: 98

Answers (6)

Raman Shrivastava
Raman Shrivastava

Reputation: 2953

What you're trying is not working because B's type is not B but Test<T>.B

To get this to work, make class B static.

public static class B{ }

Upvotes: 1

swingMan
swingMan

Reputation: 752

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();

Upvotes: 2

Turing85
Turing85

Reputation: 20185

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.

Upvotes: 2

celticminstrel
celticminstrel

Reputation: 1679

B is an inner class. It cannot exist without an instance of Test. Thus, it also depends on any type parameters of Test. When compiled, class B is transformed into the following:

public class Test$B {
  public Test$B(Test paramTest) {}
}

(That's what you'll get if you compile it and then decompile it.)

You can see that it takes an Test in its constructor. Though type parameters are erased when compiling, if you wrote a class like that yourself, you would probably give it a type parameter to be passed along to Test.

Upvotes: 1

M A
M A

Reputation: 72844

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.

Upvotes: 3

Andy Thomas
Andy Thomas

Reputation: 86411

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!

Upvotes: 5

Related Questions