3

I have the following fragment of code:

class BaseClass {
    public Integer getX() {
        return 5;
    }
}

class InheritedClass extends BaseClass implements Interface {
}

interface Interface {
    public Number getX();
}

public class Test5 {
    public static void main(String[] args) throws Exception {
        System.out.println(InheritedClass.class.getMethod("getX").getReturnType());
    }
}

this code returns java.lang.Number, which is very strange to me, because BaseClass's getX method returns java.lang.Integer. And the most interesting is that if BaseClass implements Interface, the returned type is java.lang.Integer... Is this a normal behaviour?

1
  • I agree that this looks odd. But so does your entire inheritance arrangement. :) Commented Mar 7, 2013 at 15:16

4 Answers 4

2

Here is what I think happens.

By simultaneously extending BaseClass and implementing Interface, the subclass promises to provide two getX() methods:

public Integer getX();
public Number getX();

Since you can't overload on return type, there can only be one method. Furthermore, its return type has to be Number rather than Integer (since you can cast the latter to the former, but not vice versa).

To reconcile all of the above, the compiler automatically generates the following method in InheritedClass:

  public java.lang.Number getX();
    Code:
       0: aload_0       
       1: invokevirtual #22                 // Method getX:()Ljava/lang/Integer;
       4: areturn       

As you can see, it has the signature of the method in Interface, but automatically delegates to the method in BaseClass (with an implicit upcast).

This automatically-generated method is what your reflection code is picking up.

Sign up to request clarification or add additional context in comments.

3 Comments

This is the only answer that actually makes sense to me, seeing as you cant actually implement a public Number getX() {...} method in the inherited class. +1.
But what is changed inside the InheritedClass, when BaseClass implements the Interface, so then InheritedClass.getMethod().getReturnType() returns Integer?
@GeorgiGeorgiev: I think the Interface -> Inherited chain is ignored in favour of Interface -> Base -> Inherited, and the latter narrows the return type down to Integer through covariant return types. This is just a guess though.
1

Yes, this is normal:

  • Integer is a subclass of Number
  • As of Java 5.0, it is OK for a derived class or an interface implementation method in Java to return a subclass of the return type declared in the superclass or the interface. This is called return type covariance.
  • Because InheritedClass implements the Interface, the return type of getX from that interface is used, namely, Number.

6 Comments

Ok, Inherited class implements the Interface, but new InheritedClass().getX() returns Integer, not Number...
@GeorgiGeorgiev an Integer inheriting Number means that an Integer is a Number, so getX returns a Number that happens to be an Integer.
covariant return types are perfectly fine, but what's going on here is contravariant return types. InheritedClass.getX returns a Number while BaseClass.getX returns an Integer. Return types are allowed to get less specific as you go up the hierarchy, not more specific.
@Jeffrey That is a different way of saying that return types are allowed to go more specific as you go down the inheritance hierarchy, right?
@dasblinkenlight Correct, but in this case the return type is getting less specific as you go down the inheritance hierarchy. (InheritedClass.getX returning a Number is less specific than BaseClass.getX returning an Integer).
|
0

The relevant section of the JLS is §8.4.8.4:

It is possible for a class to inherit multiple methods with override-equivalent signatures (§8.4.2).

If one of the inherited methods is not abstract... the method that is not abstract is considered to override, and therefore to implement, all the other methods on behalf of the class that inherits it.

The two methods we are considering here are:

  • public Integer getX();
  • public abstract Number getX();

SinceBaseClass.getX is not abstract, and it is return-type-substitutable (Integer is a subclass of Number) for Interface.getX, BaseClass.getX is chosen to override Interface.getX.

Which is strange since that's not the result you are seeing. However, if you try to define a method public Number getX() in InheritedClass, you will receive an error, which is consistent with the above.

Comments

-1

This is a function of the Java framework 1.6 which includes Generics. Integer and Double are a subtype of Number.

2 Comments

How does this involve Generics?
Receiving the type number is due that is the superclass. You can use ? extends Number to put Interger and doubles into a list. ? super type Number for an actual type. It is all based on leveraging class properties and code resuse.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.