Reputation: 252
I have a class, A
:
import java.util.ArrayList;
import java.util.List;
public class A {
protected List<Object> objects;
public A() {
objects = new ArrayList<Object>();
}
public A(List<Object> objects) {
this.objects = objects;
}
public List<Object> getObjects() {
return objects;
}
public void addObject(Object o) {
getObjects().add(o);
}
}
I want to subclass it with a class called B
, but changing the objects
field to a List<Number>
:
import java.util.List;
public class B extends A {
@Override
public List<Number> getObjects() {
return (List<Number>) super.getObjects();
}
@Override
public void addObject(Object o) {
getObjects().add((Number) o);
}
}
This, however, throws a compiler error. How can I do this correctly?
Upvotes: 0
Views: 841
Reputation: 3831
This is a key subtlety of how generics work in Java. If a type T
extends a type U
, we would expect that List<T>
extends List<U>
. But that's not the case. So when you try to return List<Number>
as a subtype of List<Object>
the compiler complains.
Note- the complaint isn't about the casting you do inside the function body, which is in itself dangerous. It's about the return type of the function which claims to be an override. In fancy terms, the return type is not "covariant" with the method in the superclass: https://www.tutorialspoint.com/Covariant-return-types-in-Java.
So that explains the "why" behind the compiler error.
As for the "how" to do this correctly. Without seeing the use case, I must say Bret C's Answer is the way I would do it.
Upvotes: 0
Reputation: 4199
Introduce a type parameter to your A class...
import java.util.ArrayList;
import java.util.List;
public class A<T> {
protected List<T> objects;
public A() {
objects = new ArrayList<T>();
}
public A(List<T> objects) {
this.objects = objects;
}
public List<T> getObjects() {
return objects;
}
public void addObject(T o) {
getObjects().add(o);
}
}
Now B doesn't actually need to override the methods...
public class B extends A<Number> {
}
Upvotes: 3