Java de ligação dinâmica
-
19-08-2019 - |
Pergunta
Eu estou praticando para um exame, e encontrou um problema de amostra que me deixa totalmente perdido. Para o seguinte código, encontrar o que a saída é:
class Moe {
public void print(Moe p) {
System.out.println("Moe 1\n");
}
}
class Larry extends Moe {
public void print(Moe p) {
System.out.println("Larry 1\n");
}
public void print(Larry l) {
System.out.println("Larry 2\n");
}
}
class Curly extends Larry {
public void print(Moe p) {
System.out.println("Curly 1\n");
}
public void print(Larry l) {
System.out.println("Curly 2\n");
}
public void print(Curly b) {
System.out.println("Curly 3\n");
}
}
public class Overloading_Final_Exam {
public static void main (String [] args) {
Larry stooge1 = new Curly();
Moe stooge2 = new Larry();
Moe stooge3 = new Curly();
Curly stooge4 = new Curly();
Larry stooge5 = new Larry();
stooge1.print(new Moe());
((Curly)stooge1).print(new Larry());
((Larry)stooge2).print(new Moe());
stooge2.print(new Curly());
stooge3.print(new Curly());
stooge3.print(new Moe());
stooge3.print(new Larry());
((Curly)stooge3).print(new Larry());
((Curly)stooge3).print(new Curly());
stooge4.print(new Curly());
stooge4.print(new Moe());
stooge4.print(new Larry());
stooge5.print(new Curly());
stooge5.print(new Larry());
stooge5.print(new Moe());
}
}
Eu tive as minhas ideias em mente, mas, em seguida, quando eu corria o java, eu tenho algo totalmente diferente:
Curly 1 Curly 2 Larry 1 Larry 1 Curly 1 Curly 1 Curly 1 Curly 2 Curly 3 Curly 3 Curly 1 Curly 2 Larry 2 Larry 2 Larry 1
As primeiras queridos estão OK, mas então eu realmente não entendo. Alguém tem uma boa explicação para este problema?
Graças
Solução
Gostaria de começar por fazer um desenho ...
Moe - print(Moe)
|
Larry - print(Moe), print(Larry)
|
Curly - print(Moe), print(Larry), print(Curly)
Então gostaria de manter o controle das variáveis:
- Larry - stooge1 -> Curly
- Moe - stooge2 -> Larry
- Moe - stooge3 -> Curly
- Curly - stooge4 -> Curly
-
Larry - stooge5 -> Larry
-
stooge1.print(new Moe())
- stooge1 -> Curly por isso chama Curly.print (Moe)
-
((Curly)stooge1).print(new Larry());
- stooge1 -> Curly por isso chama Curly.print (nova Larry ())
-
((Larry)stooge2).print(new Moe());
- stooge2 -> Larry assim chama Larry.print (novo Moe ());
-
stooge2.print(new Curly());
Ok, isso é onde fica um pouco mais complicado (desculpe eu parei um antes aqui)- stooge2 é declarado para ser um Moe. Então, quando o compilador está olhando para o que chamar ele vai chamar o método de impressão (Moe). Em seguida, em tempo de execução ele sabe que stooge2 é um Larry para que ele chama o método Larry.print (Moe).
etc ...
Deixe-me saber se segue que todo o caminho não funciona para você.
(atualizado para esclarecer o próximo)
Portanto, a regra geral é:
- os olhares do compilador no tipo de variável para decidir o método a chamada.
- a aparência de tempo de execução na classe real que a variável é ponto em que decidir onde obter o método de.
Então, quando você tem:
Moe stooge2 = new Larry();
stooge2.print(new Moe());
o compilador diz:
- pode Larry ser atribuído a stooge2? (Sim como Larry é uma subclasse de Moe)
- não Moe tem um método print (Moe)? (Sim)
o tempo de execução diz:
- eu deveria chamar o método print (Moe) neste objecto aqui ... stooge2
- stooge2 é ponto de cada Larry.
- Eu vou chamar o método print (Moe) na classe Larry.
Depois de ter trabalhado tudo o que fora tentar se livrar de alguns dos métodos e ver como isso muda as coisas.
Outras dicas
Na verdade, este problema não é tão simples como parece, já que Java é tanto estática e ligada dinamicamente. Você tem que entender onde cada um é aplicado antes de você vai entender todos os resultados que estão recebendo a partir deste exercício.
A regra geral mencionado por TofuBeer só é correta no caso de ligação dinâmica. Na ligação estática, as decisões são feitas apenas em tempo de compilação.
Seus exemplo misturas a ligação dinâmica (quando os métodos são substituídas) e estáticas de ligação (quando os métodos são sobrecarregados).
neste questão para mais detalhes .
Uma dica é desconsiderar o valor do lado esquerdo quando se olha para objetos. Em vez disso, olhar para o valor do direito durante a declaração, este é o valor real do objeto.