Отправка метода Java с нулевым аргументом

Почему (очевидно) имеет значение, передаю ли я null в качестве аргумента напрямую или передаю Object, которому я присвоил значение null?

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, но мой все равно не компилируется. Единственная разница, которую я вижу, заключается в том, что методы Хемаля являются статическими, а мои — нет. Но я действительно не понимаю, почему это должно иметь значение...?

Обновление 2: решено. В моем классе был еще один метод foo(Runnable), поэтому диспетчер не мог однозначно выбрать единственный наиболее конкретный метод. (См. мой комментарий во втором ответе Хемаля.) Спасибо всем за вашу помощь.


person Yang Meyer    schedule 18.12.2008    source источник


Ответы (4)


Какую версию Java вы используете? С 1.6.0_11 код (вставленный ниже) компилируется и запускается.

Я уверен, что очевидно, почему foo(testVal) переходит к foo(Object).

Причина, по которой foo(null) переходит к foo(String), немного сложна. Константа null имеет тип nulltype, который является подтипом всех типов. Итак, этот nulltype расширяет String, который расширяет Object.

Когда вы вызываете foo(null), компилятор ищет перегруженный метод с наиболее конкретным типом. Поскольку String является более конкретным, чем Object, вызывается именно этот метод.

Если бы у вас была другая перегрузка, такая же конкретная, как 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)");
  }

}
person Miserable Variable    schedule 18.12.2008
comment
Только что проверил это, и я ошеломлен тем, что (а) 6u11 не говорит, что это неоднозначно, и (б) что null разрешается в String, а не в Object. Узнавайте что-то новое каждый день - +1 за урок. - person Lawrence Dol; 18.12.2008
comment
@Software Monkey: Как только вы признаете, что константа null имеет нулевой тип, а нулевой тип является подтипом всех типов, это совершенно очевидно. Объект ‹ Строка ‹ nulltype. Поэтому String предпочтительнее Object. Рад, что это было полезно. Спасибо за +1. - person Miserable Variable; 18.12.2008
comment
Педантичность: метод переопределяет Object с помощью String. Перегрузка — это когда имя метода одно и то же, но сигнатура сильно различается. Отличный ответ. Спасибо. - person Sam; 01.12.2011

Потому что второй закомментированный вызов с нулевым значением неоднозначен для компилятора. Буквальный нуль может быть строкой или объектом. В то время как присвоенное значение имеет определенный тип. Вам нужно указать ноль, например. test.foo((String)null) для устранения двусмысленности.

person Lawrence Dol    schedule 18.12.2008

Кто-нибудь пробовал пример???

С 1.6.0 foo(null) отправляется наиболее конкретному применимому методу, который является foo(String)...

Если вы добавите новый метод, скажем, foo(Integer), компилятор не сможет выбрать наиболее конкретный применимый метод и покажет ошибку.

-Патрик

person pgras    schedule 18.12.2008

Извините, что использую ответ для комментария, но мне нужно опубликовать код, который не подходит для комментария.

@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)");
  }
}
person Miserable Variable    schedule 18.12.2008
comment
Да, я почистил свой тестовый класс, чтобы опубликовать его здесь, и понял, что помимо foo(String) и foo(Object) у меня также был foo(Runnable), который, как я теперь понимаю, вызывал неоднозначность foo(null), потому что String не более конкретный, чем Runnable, и наоборот. Спасибо Hemal за вашу ценную помощь! - person Yang Meyer; 18.12.2008