Reputation: 9112
Imagine we have following classes:
public interface MyInterface<T> {
List<T> getList(T t);
}
abstract class BaseClass<T extends Number> implements MyInterface<T> {
@Override
public List<T> getList(Number t) {
return null;
}
}
class ChildClass extends BaseClass<Integer> {
@Override
public List<Integer> getList(Integer t) {
return super.getList(t); //this doesn't compile
}
}
getList
in ChildClass
doesn't compile, the output is:
abstract method getList(T) in com.mypackage.MyInterface cannot be accessed directly
I can't get why BaseClass.getList
method isn't overriden in ChildClass.
But what makes me completely confused is the fix that makes it compile:
class ChildClass extends BaseClass<Integer> {
@Override
public List<Integer> getList(Integer t) {
return super.getList((Number) t); //Now it compiles!
}
}
So I cast Integer to Number, and is solves the problem.
Could anyone explain what's going on in this code?
Upvotes: 3
Views: 389
Reputation: 30875
What is going on in the imaginary class.
abstract class BaseClass<T extends Number> implements MyInterface<T> {
@Override
public List<T> getList(Number t) {
return null;
}
}
This class has one generic parameter (T) that has to extend Number class and implement the interface MyInterface
You also Try to override a method that does not exists, because this class do not extend other any class. While a class is implementing an interface there is no need to override the interface method because the are only the description.
What happen if we remove the @override annotation.
abstract class BaseClass<T extends Number> implements MyInterface<T> {
public List<T> getList(Number t) {
return null;
}
}
In this case we do not implement the method from the interface but create a new one, a this method parameter is Number that is same type as T, it will probably cause some error that class has two the same methods. (not tested by compiler)
Them implementation of this method should look like this
abstract class BaseClass<T extends Number> implements MyInterface<T> {
public List<T> getList(T t) { //Because T is allready restricted to be Number
return null;
}
}
And when You specify the type You will not have a problem to call this method when you override it
class ChildClass extends BaseClass<Integer> {
@Override
public List<Integer> getList(Integer t) {
return super.getList(t);
}
}
In advance You don have to implement it only for return null and then override it in some child class. What You can do is create class like this
abstract class BaseClass<T extends Number> implements MyInterface<T> {
private List<T> list = new ArrayList<T>(); //The way of initialization is up to You
public List<T> getList() { //Because T is allready restricted to be Number
return list;
}
}
Upvotes: 1
Reputation: 2941
As other colleagues pointed out the reason for issue is incorrect signature of parent method. The reason why the casting works is due to the way how compiler treats generics. It guarantees that there won't be runtime ClassCastException issues if you use generic but only if you don't do casting. As soon as you did it you actually said compiler to shut up as you know better what your type really is. However after this you potentially could get ClassCastException in runtime (not in this case I assume)
Upvotes: 0
Reputation: 413866
Why isn't the superclass method defined as
public List<T> getList(T t)
?
Upvotes: 2
Reputation: 3560
Your base class should look like:
abstract class BaseClass<T extends Number> implements MyInterface<T> {
@Override
public List<T> getList(T t) {
return null;
}
}
You weren't using T, but the Number class as a parameter.
Upvotes: 5
Reputation: 15008
It doesn't override because the abstract method takes a Number as a parameter and the concrete method takes an Integer. They must be the same in order to override.
You should change your abstract class implementation to take type T as a parameter.
Upvotes: 2