O mecanismo de ligação dinâmica determina que, na invocação de um método m
, a versão do método que é executada é a que está acessível na classe correspondente ao tipo concreto do objeto alvo dessa invocação.
No exemplo seguinte,
o método público m
declarado na classe A2
é redefinido na subclasse B2
;
no método n
, definido na classe A2
e herdado pela classe B2
, a instrução return 2 * m();
(que é equivalente a return 2 * this.m();
), invoca o método m
sobre o objeto corrente;
A2
, a versão de m
que é invocada é a definida em A2
;B2
, é a versão redefinida em B2
que é invocada.xpublic class A2 {
public int m(){
return 3;
}
public int n(){
return 2 * m();
}
}
public class B2 extends A2 {
public int m(){
return 0;
}
}
Nas instruções seguintes, numa qualquer classe cliente das classes A2
e B2
, o método n
é invocado sobre dois objetos diferentes, um do tipo A2
e outro do tipo B2
.
xA2 oa = new A2();
B2 ob = new B2();
System.out.println(oa.n()); // imprime 6 no standard output
System.out.println(ob.n()); // imprime 0 no standard output
A mesma versão do método n
é executada nas duas invocações pois ele não é redefinido na classe B2
, ou seja, é herdado. Neste método n
há uma invocação de m
sobre o objeto corrente, por isso a diferença dos resultados é devida à versão do método m
que é invocada – na primeira vez é a versão da classe A2
, que retorna 3 (o qual, multiplicado por 2 dá 6), e na segunda vez é a versão da classe B2
, que retorna zero (o qual, multiplicado por 2 dá zero).
Se o método m
fosse privado em vez de público, como na classe A3
abaixo, então não haveria redefinição de m
na classe B3
. Logo, o método n
invoca sempre o método m
da classe A3
, mesmo que o tipo concreto do objeto corrente seja B3
.
xxxxxxxxxx
public class A3 {
private int m(){
return 3;
}
public int n(){
return 2 * m();
}
}
public class B3 extends A3 {
public int m(){
return 0;
}
}
As instruções seguintes, numa qualquer classe cliente de A3
e B3
, dão os resultados indicados.
xA3 oa = new A3();
B3 ob = new B3();
System.out.println(oa.n()); // imprime 6 no standard output
System.out.println(ob.n()); // imprime 6 no standard output
Quando um atributo é acedido diretamente por uma classe cliente (por exemplo, porque é public
), é o tipo declarado da referência (e não o seu tipo concreto, como na invocação de métodos de instância) que define o atributo a aceder.
Exemplo de instruções numa classe cliente das classes A
e B
da secção 13.1.8:
xxxxxxxxxx
System.out.println("AA" + oa.x); // imprime AA0 no standard output
System.out.println("BB" + ob.x); // imprime BB5 no standard output
System.out.println("AB" + oab.x); // imprime AB0 no standard output
Anterior: 15.3. Ligação dinâmica
Seguinte: 15.5. Herança de contratos versus redefinição