David Thielen
David Thielen

Reputation: 32926

Can a java method implementing a base class method return an inherited class?

Let's say I have the standard Draw class with inherited classes of Circle and Square. Is there a way to do the following? Maybe with generics?

class Draw {
  public abstract Draw duplicate();
}

class Circle extends Draw {
  public Circle duplicate() {
    return new Circle();
  }
}

class Square extends Draw {
  public Square duplicate() {
    return new Square();
  }
}

Upvotes: 6

Views: 2195

Answers (4)

ssssteffff
ssssteffff

Reputation: 974

I think what you want to do is the following:

public abstract class Draw<T extends Draw> {
    public abstract T duplicate();
}

public class Circle extends Draw<Circle> {
    @Override
    public Circle duplicate() {
        return new Circle();
    }
}

public class Square extends Draw<Square> {
    @Override
    public Square duplicate() {
        return new Square();
    }
}
  1. Use of the generics (with constraint on T, that should extend Draw, to avoid weird inheritance such as Circle extends Draw<List>)
  2. Add abstract keyword to the Draw class

Then, you can do the following:

Square originalSquare = new Square();
Circle originalCircle = new Circle();

Square duplicatedSquare = originalSquare.duplicate();
Circle duplicatedCircle = originalCircle.duplicate();

EDIT

Without the generics, you could do something like this:

public abstract class Draw {
    public abstract Draw duplicate();
}

public class Circle extends Draw {
    @Override
    public Circle duplicate() {
        return new Circle();
    }
}

public class Square extends Draw {
    @Override
    public Square duplicate() {
        return new Square();
    }
}

Thanks to Pavel, rgettman and Enno Shioji , I did not know about "covariant return type".

Upvotes: 1

rgettman
rgettman

Reputation: 178263

Yes, it is possible to have an overriding method return a type that is a subclass of the superclass method's return type. This technique, called "covariant return types", is described at the bottom of a Java tutorial on return types. This works because a Circle and a Square are Draws, so even if you have a superclass reference, and you don't know or care which subclass you really have, you still are guaranteed to get back a Draw.

Incidentally, to get your code to compile, you just need to make the Draw class abstract. Everything else, including the covariant return types, looks fine.

Upvotes: 4

Stephan
Stephan

Reputation: 43013

I would use generics here:

class Draw<T> {
  public abstract T duplicate();
}

class Circle extends Draw<Circle> {
  @Override
  public Circle duplicate() {
    return new Circle();
  }
}

class Square extends Draw<Square> {
  @Override
  public Square duplicate() {
    return new Square();
  }
}

Upvotes: 1

Enno Shioji
Enno Shioji

Reputation: 26882

Yes, you can since Java 5.

Since Java 5, a method in a subclass may return an object whose type is a subclass of the type returned by the method with the same signature in the superclass. (source). This is called covariant return types.

Upvotes: 4

Related Questions