Resolução de sobrecarga, que método é chamado

8

Suponhamos que eu tenha uma ComponentBaseturma, filha ObjectContextDecoratore neta de ObjectContext.

public class ComponentBase extends ObjectContextDecorator {
}

public class ObjectContextDecorator extends ObjectContext {

    public void set(String objectTypePath, String characteristicName, Object value) {
        //...
    }
}

public class ObjectContext {
    public void set(String characteristicName, Object value, boolean forced) {
       //...
    }
}

Os setmétodos ObjectContextDecoratore ObjectContextsão muito semelhantes. Considere este código de exemplo:

ComponentBase base = new ComponentBase();
base.set(""OTM4E_EFFLEVEL"", ""IE1 / STD"", true);

As assinaturas dos dois métodos se encaixam na que está sendo chamada corretamente. Não consigo alterar as assinaturas dos métodos, pois esse não é o meu código.

Como o compilador sabe qual método eu pretendia chamar?

Eu sei que no IDE você pode apontar para qual método você realmente deseja chamar, mas nessa situação, estou usando um carregador de classes para carregar uma classe que possui um método que contém o código de exemplo.

Gabriel Robaina
fonte
Eles são semelhantes, mas diferentes - não há ambiguidade se você passar String, String, boolean. O método mais específico será chamado. Isso tudo está no JLS.
Dave Newton
Qual é o mais específico? No meu entender, os dois são igualmente específicos.
Gabriel Robaina 22/01
3
Por favor, consulte JLS§15.12.2. Etapa 2 em tempo de compilação: determine a assinatura do método, onde as regras para isso são descritas em detalhes. Especialmente 15.12.2.5. Escolhendo o método mais específico .
Zabuzard 22/01
1
Dito isto, mesmo que o compilador e os IDEs possam descobrir qual deles é chamado, as regras são complexas e é muito difícil para um ser humano descobrir isso. Então, eu renomearia um dos métodos para torná-lo óbvio.
JB Nizet 22/01
2
Nota lateral, as strings java usam apenas uma citação dupla (como "this")
OscarRyz 22/01

Respostas:

2

Como o compilador sabe qual método eu pretendia chamar?

Ele verifica os argumentos e determina qual deles é mais específico, seguindo as regras descritas na JLS §15.2

No seu caso, a ligação:

base.set("OTM4E_EFFLEVEL", "IE1 / STD", true)

os argumentos são String, String,boolean

Que corresponde à primeira classe ( nomes de parâmetros alterados por brevidade )

public class ObjectContext {
    public void set(String s, Object o, boolean b){
       //...
    }
}

A segunda classe não é chamada porque o terceiro parâmetro é um Object:

public class ObjectContextDecorator extends ObjectContext {

    public void set(String s, String ss, Object thisOneRightHere) {
        //...
    }
}

e enquanto o valor booleano truepuder corresponder se for autoboxado, o primeiro será mais específico. A regra que está sendo aplicada aqui é:

A primeira fase (§15.12.2.2) executa a resolução de sobrecarga sem permitir conversão de boxe ou unboxing

Mas, por exemplo, se você usar o wrapper de objeto Booleanna assinatura:

public class ObjectContext {
    public void set(String s, Object o, Boolean b){ //<-- third param changed from boolean to Boolean
       //...
    }
}

Em seguida, eles corresponderão e o compilador informará com a seguinte mensagem:

> A.java:25: error: reference to set is ambiguous
>     base.set("OTM4E_EFFLEVEL", "IE1 / STD", true);
>         ^   both method set(String,Object,Boolean) in ObjectContext and method set(String,String,Object) in ObjectContextDecorator match

Mas esse não é o caso no seu exemplo.

OscarRyz
fonte
4

Está tudo explicado no expressões de invocação do método JLS §15.2 . Ele mostra tudo sobre como o método correto para chamar é escolhido. E observe que isso nem sempre é bem sucedido.

No seu caso específico, os dois métodos são sobrecargas um do outro; portanto, aplica-se o §15.2.2 "Etapa 2 da compilação em tempo real: determine a assinatura do método" - qual sobrecarga a ser chamada é determinada no momento da compilação. Esta etapa é dividida em três fases.

A primeira fase (§15.12.2.2) executa a resolução de sobrecarga sem permitir a conversão de boxe ou unboxing, ou o uso de invocação de método de variável variável. Se nenhum método aplicável for encontrado durante esta fase, o processamento continuará na segunda fase.

Na primeira fase, o compilador tenta encontrar métodos aplicáveis ​​sem permitir conversões de boxe. No seu caso, para chamar a sobrecarga que leva a Object, é necessária uma conversão de boxe para converter boolean truepara o tipoObject , para que a sobrecarga não seja escolhida na primeira fase.

Se nenhum método aplicável por chamada estrita for encontrado, a busca por métodos aplicáveis ​​continuará na fase 2 (§15.12.2.3).

Caso contrário, o método mais específico (§15.12.2.5) é escolhido entre os métodos aplicáveis ​​por chamada estrita.

Bem, nós ter encontrado exatamente um método, por isso vamos basta escolher esse método. Não há ambiguidade.

Vassoura
fonte