Despacho de método Java com argumento nulo

Por que (aparentemente) faz diferença se eu passo null como um argumento diretamente, ou passo um Object que eu atribui o valor 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)"); } 

Em outras palavras, por que a segunda chamada (comentada) de foo(...) não foi enviada para foo(Object) ?

Atualização: eu uso o Java 1.6. Eu poderia compilar o código de Hemal sem problemas, mas o meu ainda não compila. A única diferença que vejo é que os methods de Hemal são estáticos, enquanto os meus não são. Mas eu realmente não vejo porque isso deve fazer a diferença …?

Atualização 2: Resolvido. Eu tinha outro método foo (Runnable) na minha class, para que o despachante não pudesse selecionar sem ambiguidade o método mais específico. (Veja meu comentário na segunda resposta de Hemal.) Obrigado a todos por sua ajuda.

Qual versão do Java você está usando? Com o 1.6.0_11, o código (colado abaixo) é compilado e executado.

Eu tenho certeza que é óbvio porque foo(testVal) vai para foo(Object) .

A razão pela qual foo(null) vai para foo(String) é um pouco complexo. A constante null é do tipo nulltype , que é um subtipo de todos os tipos. Portanto, esse tipo de nulltype estende String , que estende o Object .

Quando você chama o compilador foo(null) procura pelo método sobrecarregado com o tipo mais específico. Como String é mais específico, então Object é o método que é chamado.

Se você tivesse outra sobrecarga que fosse tão específica quanto String, digamos foo(Integer) então você obteria um erro de sobrecarga ambíguo.

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

Porque o segundo comentado invocação com nulo é ambíguo para o compilador. O literal nulo pode ser uma string ou um object. Considerando que o valor atribuído tem um tipo definido. Você precisa converter o nulo, por exemplo, test.foo ((String) null) para remover a ambigüidade.

Alguém já tentou o exemplo ???

Com 1.6.0 foo (null) é enviado para o método mais específico aplicável, que é foo (String) …

Se você adicionar um novo método, digamos foo (Integer), o compilador não poderá escolher o método aplicável mais específico e exibirá um erro.

-Patrick

Desculpe por usar uma resposta, por um comentário, mas preciso postar um código que não cabe no comentário.

@ Yang, também sou capaz de compilar e executar o seguinte. Você pode postar um código completo que compila com uma linha comentada de tal forma que, se eu remover o comentário dessa linha, ela não será compilada?

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