Sobrecarga de método para argumento nulo

133

Eu adicionei três métodos com parâmetros:

public static  void doSomething(Object obj) {
    System.out.println("Object called");
}

public static  void doSomething(char[] obj) {
    System.out.println("Array called");
}

public static  void doSomething(Integer obj) {
    System.out.println("Integer called");
}

Quando estou ligando doSomething(null), o compilador lança o erro como métodos ambíguos . Assim é o problema porque Integere char[]métodos ou Integere Objectmétodos?

Phani
fonte
3
Apenas mude o Integerpara int.
Mudassir 8/03/11
2
@Mudassir: e o que exatamente isso resolveria?
Joachim Sauer
2
@Joachim Sauer: Se alterado de Integer para int, null não é referido aos tipos primitivos em Java, portanto, o compilador não emitirá erro.
Phani
@Joachim Sauer: Não vai dar o reference to doSomething is ambiguouserro.
Mudassir 8/03/11

Respostas:

211

Java sempre tentará usar a versão aplicável mais específica de um método disponível (consulte JLS §15.12.2 ).

Object, char[]e Integertodos podem assumir nullcomo um valor válido. Portanto, todas as três versões são aplicáveis, portanto, o Java precisará encontrar a mais específica.

Como Objecté o supertipo de char[], a versão do array é mais específica que a Objectversão-. Portanto, se apenas esses dois métodos existirem, a char[]versão será escolhida.

Quando as versões char[]e Integerestão disponíveis, as duas são mais específicas que Objectnenhuma, mas nenhuma é mais específica que a outra; portanto, o Java não pode decidir qual delas chamar. Nesse caso, você precisará mencionar explicitamente qual você deseja chamar lançando o argumento para o tipo apropriado.

Observe que, na prática, esse problema ocorre muito mais raramente do que se possa pensar. A razão para isso é que isso só acontece quando você está chamando explicitamente um método com nullou com uma variável de um tipo bastante inespecífico (como Object).

Pelo contrário, a seguinte invocação seria perfeitamente inequívoca:

char[] x = null;
doSomething(x);

Embora você ainda esteja passando o valor null, o Java sabe exatamente qual método chamar, pois levará em consideração o tipo da variável.

Joachim Sauer
fonte
1
Isto é afirmado para o Java 7. Isso também se aplica às versões anteriores do Java? Quero dizer: se você tiver várias assinaturas de método com parâmetros apenas ao longo de uma hierarquia de tipos, estará no lado de salvar com nulo como valor real? E se você construiu uma "hierarquia para" como no exemplo aqui, então não é?
Christian Gosch
2
Tenho certeza de que essas regras são as mesmas para pelo menos tudo desde o Java 1.1 (exceto para a adição de genéricos, obviamente).
Joachim Sauer
Isso significa que, se o compilador escolher entre doSomething (String str) e doSomething (Object obj) durante o tempo de execução com doSomething (null), doSomething (String str) será chamado.
Sameer
42

Cada par desses três métodos é ambíguo por si só quando chamado com um nullargumento. Porque cada tipo de parâmetro é um tipo de referência.

A seguir, são apresentadas as três maneiras de chamar um método específico seu com null.

doSomething( (Object) null);
doSomething( (Integer) null);
doSomething( (char[]) null);

Posso sugerir remover essa ambiguidade se você realmente planeja chamar esses métodos com nullargumentos. Esse design convida a erros no futuro.

jmg
fonte
1
Apenas Integer- char[]par é ambígua, porque em outros dois casos, compilador Java pode escolher mais escolha específica, como @JoachimSauer descrito.
precisa saber é
1
@kajacx: ​​A pergunta original do OP era sobre chamar esses métodos com nullo parâmetro Sob essa pré-condição, todos os três pares são ambíguos. Para o caso geral, concordo que apenas o Integer - char[]par é ambíguo.
jmg
what about doSomething(null)for public static void doSomething(String str) { System.out.println("String called"); } Isso retornará uma string chamada.
Sameer
É possível usar uma anotação como "anulável" ou "não anulável" e configurar as declarações para que apenas o único método com o qual você deseja obter um nulo seja utilizado para que um argumento explícito "nulo" (ainda que implícito) seja sempre selecionado sem ambiguidade uma sobrecarga específica ??
Peterk
4

nullé um valor válido para qualquer um dos três tipos; portanto, o compilador não pode decidir qual função usar. Use algo parecido doSomething((Object)null)ou melhor doSomething((Integer)null).

Lars Noschinski
fonte
Eu removi o método com o parâmetro Integer, ele está chamando a função e retornando a saída como "Array Called" , então qual é o contrato entre Array e Object ?
Phani
2
Matrizes Java também são objetos.
ZDS
2

Toda classe em Java estende a classe Object. Mesmo a classe Integer também estende Object. Portanto, tanto Objeto quanto Inteiro são considerados como instância de Objeto. Então, quando você passa nulo como parâmetro, o compilador fica confuso quanto ao método de objeto a ser chamado. Com o parâmetro Object ou o parâmetro Inteiro, pois ambos são objetos e sua referência pode ser nula. Mas as primitivas em java não estendem Object.

Ankit
fonte
1

Eu tentei isso e quando há exatamente um par de método sobrecarregado e um deles tem um tipo de parâmetro Object, o compilador sempre selecionará o método com um tipo mais específico. Mas quando há mais de um tipo específico, o compilador lança um erro de método ambíguo.

Como esse é um evento de tempo de compilação, isso só pode acontecer quando alguém intencionalmente passa nulo para esse método. Se isso for feito intencionalmente, é melhor sobrecarregar esse método novamente sem nenhum parâmetro ou criar outro método completamente.

Jafar Ali
fonte
0

existe uma ambiguidade por causa de doSomething (char [] obj) e doSomething (Integer obj).

char [] e Inteiro são iguais para nulos, por isso são ambíguos.

chitrendra chaudhary
fonte
0
class Sample{
  public static void main (String[] args) {
       Sample s = new Sample();
       s.printVal(null);

    } 
    public static void printVal(Object i){
        System.out.println("obj called "+i);
    }

    public static void printVal(Integer i){
        System.out.println("Int called "+i);
    }
}

A saída é Int chamada null e, portanto, a ambiguidade é com char [] e Integer

nagarjuna chimakurthi
fonte