When we say that a Base class Base
and its derived class Derived
are type compatible
we refer to the fact that a Base
reference can refer to a Derived
instance.
I.e. Base b = new Derived();
For the oposite a casting would be needed as the types are not type compatible.
Now is this concept not applicable to primitive types?
I mean this
short shortNumber = 10;
int intNumber = shortNumber;
seems like the same thing to me (as also no casting is needed and both short
and int
are integral types).
So when overiding a method in the base class, why is it acceptable that the return type be either the same or at least type compatible with the base's class return type but this is not applicable to integral types for example as well?
E.g. why is this not acceptable?
public class Person {
public int getId(){
return 1;
}
}
public class Employee extends Person {
public short getId(){
return 0;
}
}
The direct answer, why your code example is not valid, is simple: The Java language feature of covariant return types explicitly does not apply to primitives. See JLS 8.4.5 and JLS 8.4.8.3.
Autoboxing does not apply here. If you changed your return types to Integer
and Short
, they would still not be return-type-substitutable, because neither is a subclass of the other.
I can not answer the question "why does the JLS not allow covariant return types for primitives", i.e. why the language designers decided it should not be allowed.
Since Java 1.5, your shorts and ints are all auto-boxeable to Short
and Integer
, and Short does not extend Integer (e.g. it has a different MAX_VALUE).
That's one reason this would be problematic, but I think the true reasons are one of those java language design decisions: if you are going to be changing the type, we want you to be aware of it.
you can not override method on the basis of return types, it's not allowed and compiler will complain that it'll not be treated as overridden method.
Also function calls are not deterministic on the bases of return types. For example if you call
someObj.getId();
How the compiler will determine which method should be called? does not matter from the compiler point of view that you are not handling the returned value.
JLS #8.4.8.3: Requirements in Overriding and Hiding
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.
JLS #8.4.5: Method Return Type - objects and primitves are not treated in the same way (emphasis mine):
method declaration d1 with return type R1 is return-type-substitutable for another method d2 with return type R2, if and only if the following conditions hold:
- If R1 is void then R2 is void.
- If R1 is a primitive type, then R2 is identical to R1.
- If R1 is a reference type then:
- R1 is either a subtype of R2 or R1 can be converted to a subtype of R2 by unchecked conversion (§5.1.9), or
- R1 = |R2|
As for your initial example, it is called a widening conversion (short -> int) and does not apply in the context of method overriding.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With