Reputation: 63
I've made my code as generic as possible to try and help people in the future. My abstract class has a method of the type class and and an input of the type class. In the class that extends the abstract, I try to implement that method to no avail. What am I doing wrong?
public abstract class A {
public abstract A method1(A arg);
}
public class B extends A {
@Override
public B method1(B arg) { "...insert code here"} // Error: The method method1(B) must override or implement a supertype method
}
Upvotes: 5
Views: 3723
Reputation: 140544
Think about the Liskov substitution principle: in order to be indistinguishable from a superclass, the subclass must accept all of the same parameters that the superclass would; and return something that the superclass might.
Another way to put this is that the subclass method can:
Return a more specific type that the superclass method (since this is a value that the superclass might return); for example, if the superclass returns Object
, the subclass can return a String
, because all String
s are Object
s.
This is called a covariant return type, and is permitted in Java. Subclasses can not only return more specific return types, they can also throw more specific checked exceptions than the superclass; but they can also not declare that they throw the checked exceptions thrown by the superclass method.
Accept a more general type than the superclass method (since this allows the subclass to accept all parameters that the superclass would).
This would be called a contravariant parameter type; but it is not permitted in Java. The reason is to do with the way that overloads are selected in Java: unfortunately, the method signatures (which includes the parameter types, but not the return type) have to be identical.
The relevant section of the language spec is JLS Sec 8.4.8.3.
Your problem is making the parameter type B
: this is more specific than A
, so an instance of B
is not substitutable for an instance of A
, because A.method1
accepts a parameter A
, whereas B.method1
does not.
Make B.method1
take a parameter of type A
.
Upvotes: 3
Reputation: 131526
To achieve what you want : associating the type of the argument to the declared class, you could use generics.
abstract class :
public abstract class A <T extends A<T>> {
public abstract T method1(T arg);
}
concrete class :
public class B extends A<B> {
@Override
public B method1(B arg) {
...
return ...
}
}
Upvotes: 3
Reputation: 93
Every thing you have written is right except overidden method argument type,you can't change the signature of superclass abstract method while overiding in subclass.
public abstract class A {
public abstract A method1(A arg);
}
public class B extends A {
@Override
public B method1(A arg) { "...insert code here"} // Error: The method method1(B) must override or implement a supertype method
}
Upvotes: 1
Reputation: 680
The type and no of parameter should remain. The return type, if it is of primitive type, should remain same, but if it is of reference type then it can be of subclass type.
In your case change this public B method1(B arg) { "...insert code here"}
to public B method1(A arg) { "...insert code here"}
Upvotes: 2
Reputation: 15714
The contract of A.method1
means that every object that is an A
must have a method1
which can take any A
object.
In the case of B.method1
, it can take a B
object, but it cannot take another A
.
Upvotes: 0