Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I get "Illegal generic type for instanceof"?

Tags:

java

generics

Given:

public class C<T> {     private class D {         public boolean equals( Object o ) {             if ( !(o instanceof D) )    // line 4                 return false;             D other = (D)o;             // line 6             return i == other.i;         }         int i;     } } 

I get:

C.java:4: illegal generic type for instanceof           if ( !(o instanceof D) )                               ^ 

I also get an "unchecked cast" warning about line 6. Why? The o is not a generic type -- it's just a plain Object. How can I correctly implement equals() by both checking for and casting to an instance of D?

Note: Obviously, this code example is a whittled-down version of my actual code. The real classes for C and D are much larger and D is a private inner class of C used by its implementation.

FYI: The real D does make use of the generic parameter T.

like image 767
Paul J. Lucas Avatar asked Oct 23 '10 00:10

Paul J. Lucas


People also ask

Which reference types Cannot be generic?

Almost all reference types can be generic. This includes classes, interfaces, nested (static) classes, nested interfaces, inner (non-static) classes, and local classes. The following types cannot be generic: Anonymous inner classes .

Why is generic type safe?

By using generics, programmers can implement generic algorithms that work on collections of different types, can be customized, and are type safe and easier to read.


1 Answers

The o is not a generic type -- it's just a plain Object.

That's not the problem. The problem ... and the root cause of both compilation errors ... is that D is a generic class. And it is generic because it is a non-static nested class in a generic class. Its fully qualified name would be some.pkg.C<T>.D.

FYI: The real D does make use of the generic parameter T.

And the fact that it could make use of T is what makes D a generic class.

The reason that you cannot use instanceof D or (D) is generic type erasure. Basically, the runtime cannot distinguish between the types of (say) C<String>.D and C<Integer>.D. And since it cannot do that, it cannot determine if instanceof D should return true or false or if (D) should succeed or throw ClassCastException.

One solution would be to declare D as static. But that will not work with your "real D" because a static class cannot make use of a generic type parameter from the enclosing class(es). Your "FYI" says that it does that.

Another solution is to instantiate the outer class C passing it the actual type of T as a java.lang.Class<T> instance. Then use this Class instance to implement the runtime type checks and casts as required. This is likely to be messy.

The third solution is to carefully analyze the code and determine if it is safe to a @SuppressWarning annotations to suppress the "unsafe cast" etc warnings.

What type erasure? 'o' is of type Object directly.

Actually Object is the declared type of the o variable. The actual object will most likely have some other type, and it is that type that (if it is a D instance for example) will have been subjected to type erasure.

like image 176
Stephen C Avatar answered Sep 25 '22 01:09

Stephen C