Изпращане на 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 без проблеми, но моят все още не се компилира. Единствената разлика, която виждам е, че методите на 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
Току-що тествах това и съм зашеметен, че (a) 6u11 не казва, че е двусмислено и (b) че null се разрешава на String, а не на Object. Научавайте нещо ново всеки ден - +1 за урока. - person Lawrence Dol; 18.12.2008
comment
@Software Monkey: След като приемете, че константата null е от нулев тип и нулевият тип е подтип на всички типове, това е съвсем очевидно. Обект ‹ Низ ‹ нулев тип. Така че String е за предпочитане пред Object. Радвам се, че това беше полезно. Благодаря за +1. - person Miserable Variable; 18.12.2008
comment
Педантичност: методът заменя Object с String. Претоварването е, когато името на метода е същото, но подписът варира по-широко. Отличен отговор. Мерси. - person Sam; 01.12.2011

Тъй като второто коментирано извикване с null е двусмислено за компилатора. Литералът нула може да бъде низ или обект. Докато присвоената стойност има определен тип. Трябва да кастнете нулата, напр. 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