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
.
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 .
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With