Reputation: 119
I have read similar questions, and know generic erasures will cause this error IN SAME CLASS. But I cannot understand why following code dont work.
I designed some examples. And found many many things confusing.
public static class Father<S> {
public void foo(Set<String> s) {...}
public void bar(S s) {...}
public void baz(String s) {...}
}
public static class Son<E> extends Father {
public void foo(Set<String> s) {...} **// error**
public void bar(E e) {...} **// error**
// public void bar(Object e) {...} // This works
public void baz(String s) {...}
}
public static class Daughter<E> extends Father<T> {
public void foo(Set<String> s) {...} **// error**
public void bar(Object e) {...}
public void baz(String s) {...} **// error**
}
As you can see, I got several erros. Here is my questions:
Father
and Son
. Why does baz
work, while foo
does not?bar
in Son
. Why Object e
works, while E e
fails? I think E
will be erased to Object
?Daughter
, why baz
fails, comparing to Son
?Please anyone tell me why this occurs? Many thanks! (I know I should not use raw classes. But why this causes error? )
Upvotes: 2
Views: 597
Reputation: 131346
Here :
public class Son<E> extends Father {
You are using a raw Father
in the definition of the class extending.
It is a bad practice.
You should rather write :
public class Son<E> extends Father<E> {
Using raw types has also consequences in terms of inheritancy.
From the JLS :
The superclasses (respectively, superinterfaces) of a raw type are the erasures of the superclasses (superinterfaces) of any of the parameterizations of the generic type.
and :
The supertype of a class may be a raw type. Member accesses for the class are treated as normal, and member accesses for the supertype are treated as for raw types.
As a consequence, Son
doesn't consider generics in the parent class.
For Son
, this inherited method :
public void foo(Set<String> s) {
}
is indeed bound as :
public void foo(Set s) {
}
So, the child and the parent methods have the same erasure but the child method doesn't override the parent method as you don't use exactly the same type :
public void foo(Set<String> s) {...} **// error**
If you override in this way to be conform to the raw version of the Father
:
public void foo(Set s) {...}
it will compile.
For bar()
method with generics, it is exactly the same thing.
This :
public void bar(E e)
will be bound as :
public void bar(Object e)
And you get the same problem...
I will not explain all the points as I don't think that it is helpful.
What you get is the result of bad practices.
The morale is you have not to use raw types for class designed to work with generics as it may create serious side effects on their initial intention and usage of the class.
This
public static class Son<E> extends Father {
should be :
public static class Son<E> extends Father<E> {
And this :
public static class Daughter<E> extends Father<T> {
should be :
public static class Daughter<E> extends Father<E> {
Upvotes: 1
Reputation: 393811
The issue is that Son<E>
extends a raw Father
class.
Therefore foo
and bar
of the Son
class don't override
public void foo(Set<String> s) {}
public void bar(S s) {}
of the Father
class, which (after erasure) become
public void foo(Set s) {}
public void bar(Object s) {}
and have the same erasure of the methods of the same name in the Son
class.
Changing the declaration of Son
to
public static class Son<E> extends Father<E>
will resolve the errors.
The baz
method has no issues since it has no generic arguments, so baz
of the sub-class overrides baz
of the base-class.
In your Daughter
class, it's not clear where T
is coming from. If you change T
to E
, all the errors go away.
Oh, and void bar(Object e)
works in the original example since it overrides void bar(S s)
of Father
(due to the fact the Son
extends a raw Father
).
Upvotes: 1