Java Method Dispatch with Null Argument

Java method dispatch with null argument

Which version of Java are you using? With 1.6.0_11 the code (pasted below) compiles and runs.

I am sure its obvious why foo(testVal) goes to foo(Object).

The reason why foo(null) goes to foo(String) is a little complex. The constant null is of type nulltype, which is a subtype of all types. So, this nulltype extends String, which extends Object.

When you call foo(null) compiler looks for the overloaded method with most specific type. Since String is more specific then Object that is the method that gets called.

If you had another overload that was as specific as String, say foo(Integer) then you would get a ambiguous overload error.

class NullType {

public static final void main(final String[] args) {
foo();
}

static void foo()
{
Object testVal = null;
foo(testVal); // dispatched to foo(Object)
foo(null); // compilation problem -> "The method foo(String) is ambiguous"
}

public static void foo(String arg) { // More-specific
System.out.println("foo(String)");
}

public static void foo(Object arg) { // Generic
System.out.println("foo(Object)");
}

}

Using null in overloaded methods in Java

If you were asked what is more specialized "String" or "Object", what would you say? Evidently "String", right?

If you were asked: what is more specialized "String" or "Integer"? There is no answer, they are both orthogonal specializations of an object, how can you choose between them? Then you must be explicit regarding which one you want. For instance by casting your null reference:

question.method((String)null)

When you use primitive types you do not have that problem because "null" is a reference type and cannot conflict with primitive types. But when you use reference types "null" could refer to either String or Integer (since null can be cast to any reference type).

See the answer in the other question that I posted in the comments above for further and deeper details and even a few quotes from the JLS.

Overloading method calls with parameter null

It always uses the most specific method according to the Java specs, section 15.12.2.5.

The intro is reasonably specific about it:

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.

The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error.

Generally speaking, and at least for code readability, it's always best to try to be as explicit as possible. You could cast your null into the type that matches the signature you want to call. But that's definitely a questionable practice. It assumes everyone knows this rule and makes the code more difficult to read.

But it's a good academic question, so I +1 your question.

Strange Java null behavior in Method Overloading

why the program calls foo(String x) instead of foo(Object x)

That is because String class extends from Object and hence is more specific to Object. So, compiler decides to invoke that method. Remember, Compiler always chooses the most specific method to invoke. See Section 15.12.5 of JLS

If more than one member method is both accessible and applicable to a
method invocation, it is necessary to choose one to provide the
descriptor for the run-time method dispatch. The Java programming
language uses the rule that the most specific method is chosen.

The informal intuition is that one method is more specific than
another if any invocation handled by the first method could be passed
on to the other one without a compile-time type error.

However, if you have two methods with parameter - String, and Integer, then you would get ambiguity error for null, as compiler cannot decide which one is more specific, as they are non-covariant types.

When passing null as argument to overloaded varargs method(Object... o) and non-varargs method(Object o), why varargs method is executed?

Object[] is more specific type than Object.

According to JLS §15.12.2

If more than one member method is both accessible and applicable to a
method invocation, it is necessary to choose one to provide the
descriptor for the run-time method dispatch. The Java programming
language uses the rule that the most specific method is chosen.

The informal intuition is that one method is more specific than
another if any invocation handled by the first method could be passed
on to the other one without a compile-time error.

The same chapter also has an example exactly about the situation in question.

[...] a variable arity method is treated as a fixed arity method in the
first phase. For example, declaring m(Object...) in a class which
already declares m(Object) causes m(Object) to no longer be chosen for
some invocation expressions (such as m(null)), as m(Object[]) is more
specific.

What is the output for the following Java program where null is passed as argument for the overloaded methods?

Taken from the Java Spec:

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.

First of all: both methods are accessible (obviously) and applicable. They are both applicable, because null is of type nulltype, which is by definition a subtype of all types. String is more specific than Object, because String extends Object. If you would add the following, you will have a problem, because both Integer and String are equally "specific":

void display(Integer s) {
System.out.println("Integer method called");
}


Related Topics



Leave a reply



Submit