当参数为原义null值时,如何选择重载方法?


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

它给出了一个编译错误,提示“方法MoneyString类型的方法method(StringBuffer)不明确”


您可以将一个字符串分配给一个空值,以便它是有效的,并且Java和大多数编程语言的顺序都适合最接近的类型,然后适合对象。
JonH 2012年


6
显然,仅阅读标题的人将其关闭了。这里的实际问题是关于为什么选择特定的重载,而不是“什么是空”。
interjay 2012年

Answers:


102

字符串变量null是否指向空?

空引用可以转换为任何类类型的表达式。因此,对于String,这很好:

String x = null;

String选择此处的重载是因为Java编译器根据JLS的15.12.2.5节选择了最具体的重载。特别是:

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

在第二种情况下,这两种方法仍然适用,但是两者String都不StringBuffer比另一个更具体,因此这两个方法都不比另一个更具体,因此出现编译器错误。


3
字符串重载比对象重载更具体吗?
user1610015 2012年

12
因为Object可以采用任何类型并将其包装在中Object,而String只能采用String。在这种情况下,String与类型相比,该Object类型更为具体。
JonH 2012年

10
@zakSyed如果询问您什么是更专业的“字符串”或“对象”,您会说什么?显然是“字符串”,对不对?如果您被问到:什么是更专门的“ String”或“ StringBuffer”?没有答案,它们都是正交专业,如何在它们之间进行选择?然后,您必须明确说明要选择哪一个(即通过投射空引用question.method((String)null)
Edwin Dalorzo 2012年

1
@JonSkeet:这很有道理。因此,基本上,它会根据最特定的规则寻找一种方法,如果无法决定哪个更特定,则将抛出编译时错误。
zakSyed 2012年

3
@JonH“ null”是引用类型,如果其中一种方法接收原始类型作为参数(即int),则在选择正确的方法来调用null类型的引用时,编译器甚至不会考虑它。如果使用“ Int”表示java.lang.Integer或表示原始类型int,则令人困惑。
Edwin Dalorzo

9

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

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

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

Jon的答案很好地解释了为什么编译器选择将其扩展为String 。


我很确定类型是Void。
xavierm02 '02 -10-23

2
@ xavierm02 Java语言规范中没有提及。您能否引用您的参考,以便我们所有人都可以验证您的主张?
Edwin Dalorzo 2012年

我从没看过那件事。但是我今年夏天确实做了一些Java,您可以重载采用Object的方法和采用Void对象的方法。
xavierm02 '02 -10-23

它更多的是类而不是类型。
xavierm02 '02 -10-23

4
@ xavierm02当然可以。您可以使用所需的任何其他类型重载Java中的方法。尽管如此,这与问题或我的答案无关。
Edwin Dalorzo

2

您可以指定一个string到一个null值,它是有效的和Java和大多数编程语言的顺序是适合最接近的类型,然后到对象。


2

要回答标题中的问题:null既不是a String也不是an Object,但是可以将对a的引用分配给null

我真的很惊讶该代码甚至可以编译。以前我尝试过类似的操作,但收到编译器错误,说该调用不明确。

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

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

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

很酷的问题!


null既不是,也可以分配给两者,这就是区别,它将编译为什么不这样做-这是绝对有效的代码。
JonH 2012年

0

由于字符串类型比对象类型更具体。假设您再添加一个采用Integer类型的方法。

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

然后,您将收到一个编译器错误,指出该调用不明确。像现在一样,我们使用两种具有相同优先级的特定方法。


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

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

希望它将有助于更好地了解此案。


0

来源: https : //docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5
概念:最特定的方法
说明:如果多个成员方法都可以访问且在适用于方法调用的情况下,必须选择一个为运行时方法分派提供描述符。Java编程语言使用选择最具体方法的规则。尝试将null强制转换为特定类型,然后将自动调用所需的方法。


在第一个示例中,String扩展了Object,所以“最特定”是采用String的方法,但是在第二个示例中,String和StringBuffer 扩展了Object,因此它们同样是特定的,因此编译器无法做出选择
David Kerr

-1

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


null正如JLS中定义的,它绝对是一个值。
Sotirios Delimanolis 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.