63 votes

Pourquoi Java lier les variables au moment de la compilation?

Considérons l'exemple de code suivant

class MyClass {
    public String var = "base";

    public void printVar() {
        System.out.println(var);
    }
}

class MyDerivedClass extends MyClass {
    public String var = "derived";

    public void printVar() {
        System.out.println(var);
    }
}

public class Binding {
    public static void main(String[] args) {
        MyClass base = new MyClass();
        MyClass derived = new MyDerivedClass();

        System.out.println(base.var);
        System.out.println(derived.var);
        base.printVar();
        derived.printVar();
    }
}

il donne le résultat suivant

base
base
base
derived

Les appels de méthode sont résolus au moment de l'exécution et de la bonne méthode de remplacement est appelé, comme prévu.
Les variables d'accès est plutôt résolu au moment de la compilation que j'ai appris plus tard. Je m'attendais à une sortie en tant que

base
derived
base
derived

parce que dans la classe dérivée de la re-définition de l' var ombres celui de la classe de base.
Pourquoi la liaison de variables qui se passe au moment de la compilation et non à l'exécution? Est-ce seulement pour des raisons de performances?

46voto

manouti Points 10398

La raison est expliquée dans le Langage Java Spécification d'un exemple dans l'Article 15.11, cité ci-dessous:

...

La dernière ligne montre que, en effet, le champ qui est accessible ne dépend pas de la durée d'exécution de la classe de l'objet référencé, même si s contient une référence à un objet de la classe T, l'expression s.x se réfère à l' x champ de la classe S, parce que le type de l'expression s est S. Les objets de la classe T contenir deux champs nommés x, l'un pour la classe T et une pour sa super - S.

Ce manque de dynamique de recherche pour le domaine de l'accès permet d'exécuter les programmes de manière efficace avec la simple mise en œuvre. La puissance de la liaison tardive et prioritaire est disponible, mais uniquement lorsque les méthodes d'instance sont utilisés...

Donc oui, la performance est une raison. La spécification de la façon dont l'accès à un champ d'expression est évaluée est déclaré comme suit:

  • Si le champ n'est pas static:

    ...

    • Si le champ est un non-vide final, alors le résultat est la valeur de l'nommé membre de champ de type T trouvé dans l'objet référencé par la valeur de la Primaire.

Primaires dans votre cas se réfère à la variable derived , qui est de type MyClass.

Une autre raison, comme @Clashsoft suggéré, c'est que dans les sous-classes, les champs ne sont pas surchargée, ils sont cachés. Il est donc logique de permettre les champs de l'accès basé sur le type déclaré ou à l'aide d'un plâtre. Cela est également vrai pour les méthodes statiques. C'est pourquoi le champ est déterminée en fonction du type déclaré. Contrairement à la substituant par des méthodes d'instance où il dépend du type réel. Le JLS citation ci-dessus, en effet, mentionne cette raison implicitement:

La puissance de la liaison tardive et prioritaire est disponible, mais uniquement lorsque les méthodes d'instance sont utilisés.

25voto

Clashsoft Points 1633

Alors que vous pourriez être à droite sur la performance, il y a une autre raison pour laquelle les champs ne sont pas distribué de façon dynamique: Vous ne seriez pas en mesure d'accéder à l' MyClass.var champ à tous, si vous avez eu une MyDerivedClass de l'instance.

En général, je ne sais pas à propos de n'importe quelle langue qui a réellement dynamique à résolution variable. Mais si vous en avez vraiment besoin, vous pouvez faire des getters ou des méthodes accesseurs (qui devrait être fait dans la plupart des cas, pour éviter public champs, de toute façon):

class MyClass
{
    private String var = "base";

    public String getVar() // or simply 'var()'
    {
        return this.var;
    }
}

class MyDerivedClass extends MyClass {
    private String var = "derived";

    @Override
    public String getVar() {
        return this.var;
    }
}

5voto

alainlompo Points 1855

Le polymorphe comportement du langage java fonctionne avec des méthodes et des pas variables membres: ils ont conçu la langue pour lier les variables de membre au moment de la compilation.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X