Java: Cannot override abstract method passing subclass [duplicate] - java

This question already has an answer here:
Is it possible to override a superclass' method with a parameter extending the superclass' method parameter?
(1 answer)
Closed 6 years ago.
I have an abstract class
public abstract class SuperclassA{
public abstract void method(SuperclassB b);
}
And an implementation
public class SubclassA extends SuperclassA{
#override
public void method(SubclassB b){
}
}
where SubclassB extends SuperclassB.
My NetBeans editor complains that I am not overriding method.
What can I do to actually pass a subclass to method?

In order to override a method of the base class, the sub-class's method must have the same signature.
If you want the overridden method to accept only instances of SubclassB, you can test for it :
public class SubclassA extends SuperclassA
{
#Override
public void method(SuperclassB b){
if (!(b instanceof SubclassB)) {
// throw some exception
}
SubclassB sb = (SubclassB) b;
...
}
}
You can call that method as follows :
SuperclassA a = new SubclassA ();
a.method (new SubclassB ());

Think of the method signatures of a class or interface as a contract or a promise of what it and any subclass can do.
SuperclassA promises to do action method for any SuperclassB. In order for SubclassA to be a SuperclassA it must do action method for all SuperclassB. The issue is that it only does action method for some types of SuperclassB.
Here is the same situation with names that are easier to understand.
abstract class Pet {
// Pet methods
}
class Cat extends Pet {
// Cat methods
}
class Dog extends Pet {
// Dog methods
}
abstract class PetShop {
public abstract void groom(Pet pet);
}
The Pet shop class promises that any PetShop can groom any Pet, including dogs.
PetShop shop = new FranksPetShop();
shop.groom(new Dog());
If we define FranksPetShop like so it only defines how to groom Cat's, any other type of Pet (including dogs) is not defined.
class FranksPetShop {
#Override
public abstract void groom(Cat cat) {
// Groom that cat
}
}
To solve this FranksPetShop has to define how to groom a Pet not just a Cat.
class FranksPetShop {
#Override
public abstract void groom(Pet pet) {
// Groom that pet
}
}

Actual, Method Signature is,
public abstract void method(SuperclassB b);// into abstract class
Your overrided Method Signature must be same, Otherwise it's not
override, in fact it will be treated like overloading,
#override
public void method(SuperclassB b){
}
//OverLoad not Override
public void method(SubclassB b){
}

The method in SubclassA takes in a type of SubclassB. The method in SuperclassA is taking in a type of SuperclassB. You are not overriding the parent class method, you are overloading by using a different type.
Depending on what you are trying to accomplish, you could try this
public class SubclassA extends SuperclassA{
#override
public void method(SuperclassB b){
}
}
Which would override the method you want. As long as SubclassB is a child of SuperclassB, then you will still be able to pass SubclassB in.
You can still have an overloaded method that takes in Subclasss if you want.
public class SubclassA extends SuperclassA{
#override
public void method(SuperclassB b){
}
public void method(SubclassB b){
}
}
Take a look at this thread for more info about overloading vs overriding.

Refer to oracle documentation page on override.
An instance method in a subclass with the same signature (name, plus the number and the type of its parameters) and return type as an instance method in the superclass overrides the superclass's method.
The ability of a subclass to override a method allows a class to inherit from a superclass whose behavior is "close enough" and then to modify behavior as needed.
The overriding method has the same name, number and type of parameters, and return type as the method that it override
In your case, you did not use same method signature.
public void method(SubclassB b){
should be changed to
public void method(SuperclassB b){
Now you can use workaround suggested by Eran by using instanceof

Related

Calling a Generic Interface Method does not work

I got a generic interface with one method accepting a parameter of the generic type:
public interface ComponentRenderer<T extends GuiComponent> {
public void draw(T component);
}
Furthermore I have an abstract class, that declares a variable of this interface type using a bounded wildcard:
public abstract class GuiComponent extends Gui {
private ComponentRenderer<? extends GuiComponent> componentRenderer;
public void draw() {
this.componentRenderer.draw(this);
}
//and a setter and getter for the ComponentRenderer
}
And a subclass, wich set a implementation for the componentRenderer:
public class GuiButton extends GuiComponent {
public GuiButton(/* ... */) {
//...
this.setComponentRenderer(new FlatButtonRenderer());
}
where FlatButtonRenderer is implemented as:
public class FlatButtonRenderer implements ComponentRenderer<GuiButton> {
#Override
public void draw(final GuiButton component) {
//...
}
}
I can't see where I got something wrong, but the call componentRenderer.draw(this) in GuiComponent does not work with the following error:
As far as I understand this, it says me, that I can't use GuiComponent because it does not derive from GuiComponent, what makes no sense. I've also tried ? super GuiComponent, which will accept the draw() call, but then does not accept the implementation of FlatButtonRenderer
I do not understand this syntax error, does anyone have an idea, how I need to change the code?
EDIT:
When I use my IDE's code completion on the call of draw(), it says me, that draw accept one argument of type "null", so for some reason, it is not able to figure out, wich type the argument should be...
The problem is that ? extends GuiComponent means "one specific subtype of GuiComponent, but unknown which".
The compiler does not know that this is of the right GuiComponent subtype for the ComponentRenderer. It could be that the renderer only can work with some other specific subclass.
You have to use some kind of self-type pattern to do this in a type-safe way. That way you kind of "connect" the type variable of the renderer with the type of the GuiComponent subclass.
Example:
class Gui {}
interface ComponentRenderer<T extends GuiComponent<T>> {
public void draw(T component);
}
// T is the self-type. Subclasses will set it to their own type. In this way this class
// can refer to the type of its subclasses.
abstract class GuiComponent<T extends GuiComponent<T>> extends Gui {
private ComponentRenderer<T> componentRenderer;
public void draw() {
this.componentRenderer.draw(thisSub());
}
public void setComponentRenderer(ComponentRenderer<T> r) {}
// This method is needed for the superclass to be able to use 'this'
// with a subclass type. Sub-classes must override it to return 'this'
public abstract T thisSub();
//and a setter and getter for the ComponentRenderer
}
// Here the self-type parameter is set
class GuiButton extends GuiComponent<GuiButton> {
public GuiButton(/* ... */) {
//...
this.setComponentRenderer(new FlatButtonRenderer());
}
class FlatButtonRenderer implements ComponentRenderer<GuiButton> {
#Override
public void draw(final GuiButton component) {
//...
}
}
#Override
public GuiButton thisSub() {
return this;
}
}
This is originally (I think) called the curiously recurring template pattern. This answer explains it more.
In GuiComponent, change your declaration of componentRenderer to this:
ComponentRenderer<GuiComponent> componentRenderer;

Object of a subclass in a variable of type interface (implemente by superclass) calls superclass method?

I have an interface, a superclass that implements it, and a subclass that extends the superclass. Then I have test that creates an object of the type of the subclass, but stores it in a variable of the type of the interface. When I use a method that is defined in the interface, implemented in the superclass, and overridden in the subclass, it calls the method from the superclass. Why is this? I can't change the test class, but did I do something wrong with the subclass?
public interface SampleInterface<T extends Comparable<T>>{
void add(T element);
//other methods, etc
}
public class SampleClassA<T extends Comparable<T>> implements SampleInterface<T> {
public void add(){
System.out.println("super");
}
}
#Override
public class SampleClassB<T extends Comparable<T>> extends SampleClassA<T> {
public void add(){
System.out.println("sub");
}
}
Then I want to use the code in a test that looks like this:
private SampleInterface<Integer> test = new SampleClassB<Integer>();
test.add();
And it prints "super", but I want "sub". This is a simplified version of my code, also.

interface and inheritance: "return type int is not compatible"

public interface MyInterface{
public int myMethod();
}
public class SuperClass {
public String myMethod(){
return "Super Class";
}
}
public class DerivedClass extends SuperClass implements MyInterface {
public String myMethod() {...} // this line doesn't compile
public int myMethod() {...} // this is also unable to compile
}
When I try to compile DerivedClass it gives me the error
java: myMethod() in interfaceRnD.DerivedClass cannot override myMethod() in interfaceRnD.SuperClass
return type int is not compatible with java.lang.String
How should I solve this issue?
The error results from the fact that a call to myMethod will be ambiguous - which of the two methods should be called? From JLS ยง8.4.2:
It is a compile-time error to declare two methods with override-equivalent signatures in a class.
The return type of a method is not a part of its signature, so you are receiving an error in accordance with the statement above.
Assuming you can't simply rename the conflicting methods, you can't use inheritance in this case, and will need to use an alternative like composition:
class DerivedClass implements MyInterface {
private SuperClass sc;
public String myMethod1() {
return sc.myMethod();
}
public int myMethod() {
return 0;
}
}
You can't have two methods with the same signature but different return types.
This is because the compiler cannot know which method you are trying to invoke when you do object.myMethod();.
Method overloading is differentiated by their parameter. Here myMethod() in both interface and superclass has similar parameter signature. So you can not do this.
You can't have 2 methods with the same signature but with distinct return types. If it could be it can't be determinated wich method was invoked.
BTW all methods in interface are public and abstract.
public interface MyInterface{
int myMethod();
}
What you can do is have an interface with input parameter, this is called overloading
example:
public interface MyInterface{
String myMethod(String param);
}
and in your class
public class DerivedClass extends SuperClass implements MyInterface{
public String myMethod(){ ...}
public String myMethod(String param) {...}
}

How to refer to "this" in abstract Java class?

Is it possible in Java to use this inside a method of an abstract class, but as an instance of the subclass at hand, not just of the abstract class?
abstract class MyAbstractClass <MyImplementingClass extends MyAbstractClass> {
public abstract MyImplementingClass self();
}
which I overwrite in every subclass I with
class MyImplementingClass extends MyAbstractClass<MyImplementingClass> {
#Override public MyImplementingClass self() {
return this;
}
}
but I wonder if there are more elegant methods to do this. In particular, one that doesn't require every subclass to overwrite a routine like self().
The issue here I believe is that your self() method returns MyImplementingClass and not MyAbstractClass.
You should return a MyAbstractClass, the dynamic type of the returned object will be the relevant one.
I also do not follow why wouldn't you just use this? It returns the object itself, with the correct dynamic type, regardless of where it is called. You can cast it if you need to
When overriding methods in Java, you can override the return type to be a subclass of the original type. This code is completely valid:
abstract class MyAbstractClass {
public MyAbstractClass self() {
return this;
}
}
And the concrete class:
class MyImplementingClass extends MyAbstractClass {
#Override
public MyImplementingClass self() {
return this;
}
}
This is also why you can override clone() to return an exact type instead of just Object:
public class SomeCloneable implements Cloneable {
#Override
public SomeCloneable clone() {
return new SomeCloneable();
}
}
I believe, you can return newInstance() of a class to behave like that
#Override public MyImplementingClass self() {
return MyImplementingClass.newInstance();
}

Passing Derived Class to a method which needs to override expecting a base class

I have a class A, with an abstract method doAction(BaseClass obj) expecting a param of type BaseClass
public class A {
//....
abstract void doAction(BaseClass obj);
//....
}
Now, I have another class B which needs to extend A. However, B's doAction method needs to use an object DerivedClass which extends BaseClass.
public class B extends class A {
//..
void doAction(DerivedClass obj) {
obj.callMethodAvailableOnlyInDerivedClass();
}
}
How do I handle this situation where I need to pass param of type DerivedClass to the method to be overridden while it is expecting a BaseClass ?
Thanks!
You make the base class generic:
public class A<T extends BaseClass> {
//....
abstract void doAction(T obj);
//....
}
and the subclass parameterized with the derived class:
public class B extends A<DerivedClass> {
//..
void doAction(DerivedClass obj) {
obj.callMethodAvailableOnlyInDerivedClass();
}
}
Without generics, it's not possible because B would break the contract of A: A accepts any kind of BaseClass, but you retrict B to only accept a specific subclass. This does not respect the Liskov principle.
You can use:
public abstract class A<T extends BaseClass> {
//....
abstract void doAction(T obj);
//....
}
public class B extends class A<DerivedClass> {
//..
void doAction(DerivedClass obj) {
obj.callMethodAvailableOnlyInDerivedClass();
}
}
There is no Contra-Variance of parameters in java, since it is not safe.
Assume you have A a = new B();
And then you invoke a.doAction(new BaseClass()) What will happen?
It will cause a run time error, since B does not know "what to" with a BaseClass. java wants to avoid it - so there is no covariance of parameters.

Categories