Q1. In the below code i get the error "Name clash: The method equals(T) of type Node has the same erasure as equals(Object) of type Object but does not override it"
public class Node<T> {
public boolean equals(T b) {
return false;
}
//public boolean equals(Object b) {
// return false;
//}
}
I tried to read explanations online but still have a simple question. If after type erasure, the equivalent of public boolean equals(T b) is public boolean equals(Object b) which is perfectly valid way to override, then why the fuss?
Q2. Lets say i add the @Override annotation to public boolean equals. The error thrown this time is "The method equals(T) of type Node must override a superclass method". Again, the same argument above, since after type erasure public boolean equals(T b) is public boolean equals(Object b) why does the compiler complain?
One possible explanation i can think of is "Before type erasure the compiler tries to find a method with the signature public boolean equals(T b) in the base class, doesn't find it, and complains".
Q3. In the below code we get the error "Cannot perform instanceof check against type parameter T".
if ( b instanceof T ) {
}
Again, i get the explaination that T would be stripped out and become Object and we have no info of T at runtime. Lets say hypothetically is the compiler allowed it, wouldn’t this be a valid check i.e. if ( b instanceof Object )?
So, is the compiler complaining mainly because this is misleading (as this will always be true!) and wants you to change it? Or is there some other reason's too why this isnt a good idea.
In general, erasure is not just a simple textual replacement. These different kinds of types have specific semantic meaning. Of course a language could do anything, but would the vast consequences be actually good? In general, things are disallowed because the consequences are counterproductive.
I think the error message is just confusing you, although it is actually telling you something highly-specific. It appears to be trying to cite JLS at you.
What it means is that you've declared a method with an effectively identical signature to one in a supertype such that it would be an override, but that the override is not allowed. The message is telling you "but does not override it", because this is a fact that is mandated by the spec.
The 2nd bullet-point list in 8.4.8.3 is the stipulation that prevents your code from compiling (paraphrased):
Note that the complex rules in place here do allow the following override:
(
B.m
is a subsignature ofA.m
, but not the other way around.)Herein lies one problem. Say you were allowed to override the other way:
This is not really good because if we do
A a = new B<String>();
, we can put anything in theB<String>
. It's just weird and bad. Generics are about stronger typing.There are also more problems, for example:
Can't be done because their erasures are the same.
The whole enigma must be disallowed.
@Override
does not mean you are overriding, it just means you are asserting that you think it should be an override. You just have two errors now, because it is an error to annotate a method that is not an override with@Override
.T
andObject
are different kinds of types.T
is a type variable andObject
refers to a class declaration. Specifically the rule here is that the right-hand side must be reifiable.If it did not, if
b instanceof T
were simply equivalent tob instanceof |erasure of T|
, would that be useful? No, it would not. In fact, it would be almost completely useless. Since we always know the bound ofT
we can already always make that check.It would be extremely misleading. But let's be clear. The compiler is complaining because the language specification mandates it so. When the specification mandates something, we do not always know what its reasoning is. Just that it is so.