fweigl
fweigl

Reputation: 22018

Making return type of method implementation more concrete than abstract method

Consider this abstract class

abstract class AbstractBox {
  abstract Object getContent();
}

Now my implementation of a StringBox, but there might be other Boxes implementations that would return any type of content, preventing me from making the return type of the abstract method any more concrete:

class StringBox extends AbstractBox {
  @Override
  Object getContent() {
    return "";
  }
}

Instead of letting getContent() declaring it will return an Object where it is clear it will return a String, I could also do

class StringBox extends AbstractBox {
  @Override
  String getContent() {
    return "";
  }
}

thus clearly stating what will be returned by getContent() and still override the abstract method.

  1. Is there a name for this?
  2. Is there any downside to it?

Upvotes: 1

Views: 409

Answers (3)

davidxxx
davidxxx

Reputation: 131336

Overriding allow to specify a covariant return type and here you use it in the StringBox subclass.

This feature is available since Java 1.5.
From the JLS.Chapter 8. Classes (emphasis is mine) :

8.4.5. Method Result

...

Return types may vary among methods that override each other if the return types are reference types. The notion of return-type-substitutability supports covariant returns, that is, the specialization of the return type to a subtype.

In practice if you manipulate variables with the StringBox declared type, it has the benefit for the client of the class to return a more specific type, which is a good thing as it avoids downcasts.

For example :

StringBox box = new StringBox();
String boxContent = box.getContent();

But if you manipulate variables with the AbstractBox declared type, it doesn't have any side effect at compile time or at runtime as the client expects still to have Object as return type :

AbstractBox box = new StringBox();
Object boxContent = box.getContent();

In a general way using covariance return should be used if it makes the client code clearer and simpler (as without any cast).

Upvotes: 4

Alexey Romanov
Alexey Romanov

Reputation: 170723

  1. Yes, it's "covariant return type".

  2. The compiler still generates a "bridge method" returning Object for StringBox, so there is a very slight increase in code size (and potential decrease in performance, but that should be easily eliminated by JIT).

  3. As @khelwood mentions, you quite often want to use generics instead of covariant return type (or in addition to it).

Upvotes: 2

Veselin Davidov
Veselin Davidov

Reputation: 7071

I do believe it's not a problem. If you use the abstract class for example if you have

 AbstractBox box;

box.getContent() you will get an object and you can cast if you know the implementation

If you use the concrete implementation you get the String (which is also an object).

Another solution to that would be to use a generics method for example:

abstract class AbstractBox<T> {
  abstract T getContent();
}

and in the implementation add that as String

class StringBox extends AbstractBox<String> {
  @Override
  String getContent() {
    return "";
  }
}

I don't think it makes much difference though because you still have to use StringBox to know the implementaton

Upvotes: 0

Related Questions