98

我在一次测验中遇到了这个问题,

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 是一个指向空的字符串变量吗?

但是,当代码更改为,

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类型不明确”

4

8 回答 8

102

null 是一个指向空的字符串变量吗?

空引用可以转换为任何类类型的表达式。所以在 的情况下String,这很好:

String x = null;

之所以选择此处的String重载,是因为 Java 编译器会根据 JLS 的第 15.12.2.5 节选择最具体的重载。尤其:

非正式的直觉是,如果第一个方法处理的任何调用可以传递给另一个方法而不会出现编译时类型错误,那么一个方法比另一个方法更具体。

在您的第二种情况下,这两种方法仍然适用,但两者都String没有StringBuffer比另一种更具体,因此没有一种方法比另一种更具体,因此编译器错误。

于 2012-10-23T14:44:26.850 回答
9

此外,JLS 3.10.7还声明“null”是“null 类型”的文字值。因此存在一种称为“null”的类型。

后来,JLS 4.1声明存在一个无法声明变量的 null 类型,但您只能通过 null 文字使用它。后来它说:

空引用始终可以进行扩展引用转换为任何引用类型。

为什么编译器选择将其扩展为 String 可能会在Jon 的回答中得到很好的解释。

于 2012-10-23T14:52:34.447 回答
2

您可以将 a 分配string给一个null值,使其有效,并且 java 和大多数编程语言的顺序适合最接近的类型,然后适合对象。

于 2012-10-23T14:44:45.357 回答
2

要回答标题中的问题:null既不是 aString也不是 an Object,但是可以将任何一个的引用分配给null

我真的很惊讶这段代码甚至可以编译。我之前尝试过类似的东西,但我得到一个编译器错误,说调用不明确。

但是,在这种情况下,编译器似乎选择了食物链上最低的方法。它假设您想要该方法的最通用版本以帮助您。

我将不得不看看我是否可以挖掘在这个(看似)完全相同的场景中出现编译器错误的示例,不过......]

编辑: 我明白了。在我制作的版本中,我有两个接受 aString和 an 的重载方法Integer。在这种情况下,没有“最具体”的参数(如Objectand String),因此它不能在它们之间进行选择,这与您的代码不同。

很酷的问题!

于 2012-10-23T14:45:59.483 回答
0

因为 String 类型比 Object 类型更具体。假设您添加了一个采用 Integer 类型的方法。

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

然后你会得到一个编译器错误,说调用不明确。就像现在我们两个同样特定的方法具有相同的优先级。

于 2015-10-02T11:17:25.437 回答
0

Java 编译器将大多数派生类类型分配给 null。

这是理解它的示例:

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);
    }
}

输出: B类。

另一方面:

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);
    }
}

结果:方法 fun(C) 对于 MyTest 类型不明确

希望这将有助于更好地理解这个案例。

于 2016-11-24T11:42:50.073 回答
0

来源: https ://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5
概念:最具体的方法
说明:如果多个成员方法既可访问又可访问适用于方法调用,需要选择一个为运行时方法分派提供描述符。Java 编程语言使用选择最具体方法的规则。尝试将 null 转换为特定类型,您希望的方法将被自动调用。

于 2019-03-12T12:50:56.210 回答
-1

我也不会说。NULL 是一个状态而不是一个值。查看此链接以获取更多信息(该文章适用于 SQL,但我认为它也有助于解决您的问题)。

于 2012-10-23T14:46:55.740 回答