La raison en est que Java utilise le concept de la portée lexicale de résolution variable.
Fondamentalement, il existe deux options possibles pour résoudre les variables libres dans une fonction ("libre" ne signifie pas local et n'est pas lié aux paramètres de la fonction):
1) contre l'environnement dans lequel la fonction est déclarée
2) à l'encontre de l'environnement dans lequel la fonction est exécutée (appelé)
Java va le premier, de façon variables libres dans les méthodes sont résolus [statiquement, lors de la compilation] à l'encontre de leur portée lexicale (environnement), qui comprend:
- les paramètres de la méthode et locales variables de la méthode
- champ des déclarations dans la classe contenant la méthode de déclaration
- champ public déclarations dans la classe parent
- et ainsi de suite, jusqu'à la chaîne de l'héritage
Vous verriez ce comportement mis en œuvre dans la plupart des langages de programmation, car il est transparent pour le développeur et aide à prévenir les erreurs des ombres de variables.
C'est l'opposé de la façon dont les méthodes de travail en Java:
class A {
public void foo() {
boo();
}
public void boo() {
System.out.println("A");
}
}
class B extends A {
@Override
public void boo() {
System.out.println("B");
}
}
class Main {
public static void main(String[] args) {
B b = new B();
b.foo(); // outputs "B"
}
}
Cette dynamique d'expédition: appel de la méthode est résolu dynamiquement lors de l'exécution à l'encontre de l'objet réel, sur lequel elle est appelée.