当参数为文字空值时,如何选择重载方法?

我在一次小测验中偶然发现了这个问题,

public class MoneyCalc {


public void method(Object o) {
System.out.println("Object Verion");
}


public void method(String s) {
System.out.println("String Version");
}


public static void main(String args[]) {
MoneyCalc question = new MoneyCalc();
question.method(null);
}
}

这个程序的输出是“字符串版本”。但是我不能理解为什么向重载方法传递 null 选择字符串版本。Null 是指向虚值的 String 变量吗?

但是,当代码更改为,

public class MoneyCalc {


public void method(StringBuffer sb) {
System.out.println("StringBuffer Verion");
}


public void method(String s) {
System.out.println("String Version");
}


public static void main(String args[]) {
MoneyCalc question = new MoneyCalc();
question.method(null);
}
}

它给出了一个编译错误,说明“方法方法(StringBuffer)对于 MoneyCalc 类型是不明确的”

13915 次浏览

Is null a String variable pointing to nothing ?

A null reference can be converted to an expression of any class type. So in the case of String, this is fine:

String x = null;

The String overload here is chosen because the Java compiler picks the most specific overload, as per section 15.12.2.5 of the JLS. In particular:

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.

In your second case, both methods are still applicable, but neither String nor StringBuffer is more specific than the other, therefore neither method is more specific than the other, hence the compiler error.

You can assign a string to a null value so it is valid and the order for java and most programming languages is fit to the closest type and then to object.

To answer the question in the title: null is neither a String nor an Object, but a reference to either can be assigned to null.

I'm actually surprised this code even compiles. I tried something similar previously and I got a compiler error saying that the call was ambiguous.

However, in this case, it seems like the compiler is choosing the method which is lowest on the food chain. It's assuming that you want the least generic version of the method in order to help you out.

I'll have to see if I can dig up the example where I got a compiler error in this (seemingly) exact same scenario, though...]

EDIT: I see. In the version I made, I had two overloaded methods accepting a String and an Integer. In this scenario, there is no "most specific" parameter (as in Object and String), so it can't choose between them, unlike in your code.

Very cool question!

I would say neither. NULL is a state not a value. Check out this link for more info on this (the article applies to SQL, but I think it helps with your question as well).

Additionally, the JLS 3.10.7 also declares that "null" is a literal value of the "null type". Therefore there exists a type called "null".

Later, the JLS 4.1 states that there exists a null type of which is impossible to declare variables, but you can use it through the null literal only. Later it says:

The null reference can always undergo a widening reference conversion to any reference type.

Why the compiler chooses to widen it to String might well be explained in Jon's answer.

As String type is more specific than Object type. Let's say you add one more method that takes an Integer type.

public void method(Integer i) {
System.out.println("Integer Version");
}

Then you will get a compiler error saying that the call is ambiguous. As now we two equally specific methods with same precedence.

Java compiler gives most derived class type to assign null.

Here is the example to understand it :

class A{


public void methodA(){
System.out.println("Hello methodA");
}
}


class B extends A{
public void methodB(){
System.out.println("Hello methodB");
}
}


class C{
public void methodC(){
System.out.println("Hello methodC");
}
}


public class MyTest {


public static void fun(B Obj){
System.out.println("B Class.");
}
public static void fun(A Obj){
System.out.println("A Class.");
}


public static void main(String[] args) {
fun(null);
}
}

output: B Class.

on the other hand:

public class MyTest {


public static void fun(C Obj){
System.out.println("B Class.");
}
public static void fun(A Obj){
System.out.println("A Class.");
}


public static void main(String[] args) {
fun(null);
}
}

Result : The method fun(C) is ambiguous for the type MyTest

Hope it will help to understand this case better.

Source: https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5
Concept: Most specific method
Explanation: 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. Try casting the null on to specific type and the method you wish will be automatically called.