Reputation: 32926
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
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();
}
}
T
, that should extend Draw
, to avoid weird inheritance such as Circle extends Draw<List>
)abstract
keyword to the Draw
classThen, 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
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 Draw
s, 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
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
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