The getValue() method is overridden in two ways. Which one is correct?

My problem with the following example is that I have read that if you override a function, the return type cannot be changed unless you are overriding in a descendant object, in which case you may change the return type from ParentClass to ChildClass but that is not the case in either of these cases. We change the return type from String to Object in the first example, and from Object to String in the second one, neither of which are class A or B. Maybe it is the case that you can return a more specific type in any overridden functions?

I: This one is definitely false because you are returning a more general type when overriding.

 public class Test {
  public static void main(String[] args) {
    A a = new A();
    System.out.println(a.getValue());
  }
}

class B {
  public String getValue() {
    return "Any object";
  }
}

class A extends B {
  public Object getValue() {
    return "A string";
  }
}

II: This must be the correct one but I don't understand because I thought you could only override from returning type B in class B to type A in class A. That that was the only exception and in previous versions of Java, even that wasn't allowed so I don't see how we can change Object to String.

public class Test {
  public static void main(String[] args) {
    A a = new A();
    System.out.println(a.getValue());
  }
}

class B {
  public Object getValue() {
    return "Any object";
  }
}

class A extends B {
  public String getValue() {
    return "A string";
  }
}
Jon Skeet
people
quotationmark

The second is fine, because of this rule in JLS 8.4.8.3:

If a method declaration d1 with return type R1 overrides or hides the declaration of another method d2 with return type R2, then d1 must be return-type-substitutable (ยง8.4.5) for d2, or a compile-time error occurs.

This rule allows for covariant return types - refining the return type of a method when overriding it.

Object is the superclass of String, so it's fine for a method previously declared to return Object is refined in a subclass override to return String.

It's fine because any code which only knows about the superclass method is going to use the return value as Object, and it's fine to use any String reference as an Object reference, e.g.

String x = ...; // Anything here
Object y = x; // No problem

It sounds like you're getting confused between the two pairs of types here::

  • the class declaring the method and the class overriding it
  • the return type in the original method and the return type in the override

Those are four completely separate classes - here B, A, Object and String respectively.

people

See more on this question at Stackoverflow