A concise formulation of the rule, which Java follows when figuring out which overload to invoke, would sound something like this:
When there are several overloads, which may be invoked for a given set of parameters, the most specific one is selected.
(You can read a relevant quote from Java Language Specification in this answer.)
It's also important to know that, unlike with virtual method dispatch, overload resolution occurs at compile time, so the only thing Java has to go by when selecting the overload is the type of the reference, through which you invoke the method, not the runtime type of the object, to which said reference points.
With that in mind, let's look at the lines, which surprise you.
z.dosmth((Integer)0); // prints "X:Object"
Pay attention to the type of reference z
, through which you are invoking dosmth()
. It's X
, so the only methods, involved in overload resolution, are the ones declared in class X
. As there isn't an overload accepting Integer
in X
, the only suitable overload, void dosmth(Object obj)
, gets called.
Yes, we know that actually at run time, z
refers to an object of class Y
, which does have an overload for Integer
, but at compile time there is, in general case, no way for compiler to tell the type of the object, to which z
is going to refer in the line z.dosmth((Integer)0)
, so it's only going to concern itself with overloads, available in class X
itself.
z.dosmth(0.0); // prints "X:Double"
Same reason as the previous case. z
is a reference of type X
, suitable candidates in X
for parameter 0.0
are void dosmth(Double obj)
and void dosmth(float obj)
. 0.0
is a double literal, so Java prefers void dosmth(Double obj)
. Had it been 0.0f
(a float literal), the overload accepting float
would've been preferred.
x.dosmth(null); // prints "X:Double"
z.dosmth(null); // prints "X:Double"
This is the most interesting case. null
is compatible with both Object
and Double
. Which one is more specific, though? It's Double
, ain't it? Therefore, void dosmth(Double obj)
gets selected over void dosmth(Object obj)
.