Java方法分派中使用null参数

13

为什么直接传递null参数和传递赋有nullObject参数会产生不同的结果呢?

Object testVal = null;
test.foo(testVal);    // dispatched to foo(Object)
// test.foo(null);    // compilation problem -> "The method foo(String) is ambiguous"   

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

public void foo(Object arg) { // Generic
    System.out.println("foo(Object)");
}
换句话说,为什么被注释的第二次调用 foo(...) 没有被派发到 foo(Object) 中?
更新:我使用的是Java 1.6。我可以编译Hemal的代码,但我的代码仍然不能编译。我唯一看到的区别是Hemal的方法是静态的,而我的方法不是。但我真的不知道为什么这会有任何影响...?
更新2:问题已解决。我在类中还有另一个方法 foo(Runnable),因此派发程序无法明确地选择最具体的方法。(请参见我在Hemal的第二个答案中的评论。) 感谢大家的帮助。
4个回答

24

你使用的Java版本是哪个?在1.6.0_11下,下面粘贴的代码可以编译并运行。

很明显为什么foo(testVal)会调用foo(Object),这一点毋庸置疑。

foo(null)被调用时为什么会进入foo(String)有一定复杂性。常量null的类型是nulltype,是所有类型的子类型。因此,该nulltype延伸到String,再延伸到Object

当你调用foo(null)时,编译器会寻找具有最具体类型的重载方法。由于StringObject更具体,因此该方法被调用。

如果你还有另一个与String同样具体的重载方法,比如说foo(Integer),那么你就会遇到一个有歧义的重载错误。

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

}

刚刚测试了一下,我很惊讶的是 (a) 6u11 没有报告歧义,(b) null 解析为 String 而不是 Object。每天都会学到新东西 - 对这个教训点赞。 - Lawrence Dol
1
@软件猴子:一旦你接受了常量 null 是 null 类型,而 null 类型是所有类型的子类型,这就很明显了。Object < String < nulltype。所以,String 比 Object 更可取。很高兴这很有用。谢谢点赞。 - Miserable Variable
迂腐:该方法正在使用String覆盖Object。重载是指方法名称相同,但签名变化更大。非常好的答案。谢谢。 - Sam

2

因为第二个注释掉的调用带有null,这对编译器来说是模糊不清的。字面上的null可以是字符串或对象。而赋值的值具有明确定义的类型。您需要强制转换null,例如test.foo((String)null),以消除歧义。


1

有人尝试过这个例子吗?

在1.6.0中,foo(null)会被分派到最适用的方法foo(String)...

如果你添加一个新的方法,比如foo(Integer),编译器无法选择最具体的适用方法并显示错误。

-Patrick


1

很抱歉使用回答来代替评论,但我需要发布无法适应评论的代码。

@Yang,我也能编译和运行以下内容。你能否发布一份完整的代码,其中有一行被注释掉,以便如果我取消注释该行,则无法编译?

class NullType {

  public static final void main(final String[] args) {
    foo();
    new Test().bar(new Test());
  }

  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(Integer arg) { // More-specific
    System.out.println("foo(Integer)");
  }

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


}


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

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

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

咦,我整理了一下我的测试类打算在这里发帖,结果发现除了 foo(String) 和 foo(Object) 之外,我还有一个 foo(Runnable) - 现在我明白了会导致 foo(null) 不明确,因为 String 并不比 Runnable 更具体,反之亦然。感谢 Hemal 的宝贵帮助! - Yang Meyer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接