86 votes

Quelles sont les règles pour l'évaluation de l'ordre dans Java?

Je suis en train de lire quelques Java texte et a obtenu le code suivant:

int[] a = {4,4};
int b = 1;
a[b] = b = 0;

Dans le texte, l'auteur n'a pas donné une explication claire et l'effet de la dernière ligne est: a[1] = 0;

Je ne suis pas sûr que je comprends: comment l'évaluation se produire?

176voto

Eric Lippert Points 300275

La accepté de répondre -- précisant que c'est à cause de la priorité-et le highed upvoted réponse -- précisant que c'est en raison d'une combinaison de l'associativité et la priorité -- deux sont mauvais. (Les réponses sont à la fois maintenant supprimé). Heureusement qu'ils ont tort d'une manière qui présente une valeur éducative!

Permettez-moi de dire très clairement, parce que les gens ne comprennent pas cela tout le temps:

L'ordre d'évaluation des sous-expressions est indépendant à la fois de l'associativité et de préséance. L'associativité et la priorité de déterminer dans quel ordre les opérateurs sont exécutés, mais ne pas déterminer dans quel ordre les sous-expressions sont évaluées. Votre question est sur l'ordre dans lequel les sous-expressions sont évaluées.

Envisager A() + B() + C() * D(). La Multiplication est une priorité plus élevée qu'ailleurs, et plus est de gauche associative, donc c'est équivalent à (A() + B()) + (C() * D()) , Mais en sachant que seulement vous dit que la première addition n'arrivera pas avant la deuxième plus, et que la multiplication n'arrivera pas avant la deuxième plus. Il ne vous dit pas dans quel ordre A(), B () C() et D() sera appelée! (Cela ne doit pas vous dire si la multiplication a lieu avant ou après la première). Il serait parfaitement possible d'obéir aux règles de priorité et associativité des opérateurs par la compilation de ce que:

d = D()          // these four computations can happen in any order
b = B()
c = C()
a = A()
sum = a + b      // these two computations can happen in any order
product = c * d
result = sum + product // this has to happen last

Toutes les règles de priorité et associativité des opérateurs sont suivies -- la première addition arrive avant la seconde addition et la multiplication a lieu avant la deuxième plus. Clairement, nous pouvons faire les appels pour A(), B () C() et D() dans tout l'ordre et de toujours obéir aux règles de priorité et associativité des opérateurs!

Nous avons besoin d'une règle sans rapport avec les règles de priorité et associativité des opérateurs pour expliquer l'ordre dans lequel les sous-expressions sont évaluées. La règle de Java et C#) est "sous-expressions sont évaluées de gauche à droite". Depuis Une() apparaît à la gauche de C (), () est évalué en premier, indépendamment du fait que C() est impliqué dans une multiplication et Une() est impliqué que dans une outre.

Alors maintenant, vous avez assez d'informations pour répondre à votre question. En a[b] = b = 0 les règles d'associativité dire que c'est l' a[b] = (b = 0); , mais cela ne signifie pas que l' b=0 s'exécute en premier! Les règles de préséance dire que l'indexation est une priorité plus élevée que la cession, mais cela ne signifie pas que l'indexation s'exécute avant la valeur la plus à droite.

Les règles de priorité et associativité des opérateurs imposer les restrictions qui:

  • L'indexeur opération doit s'exécuter avant l'opération associée à la gauche de cette opération, le
  • L'opération associée à la partie droite de l'affectation de l'opération doit s'exécuter avant que associé à la gauche de cette opération.

La priorité et l'associativité de nous dire que la cession de zéro à l' b doivent se produire avant que la cession a[b]. Priorité et associativité des opérateurs ne dit rien au sujet de l' a[b] est évaluée avant ou après l' b=0.

Encore une fois, c'est la même chose que: A()[B()] = C() -- Tout ce que nous savons, c'est que l'indexation a lieu avant la cession. Nous ne savons pas si A(), B) ou C() s'exécute en premier fondé sur la priorité et l'associativité. Nous avons besoin d'une règle pour nous dire que.

La règle est, de nouveau, "quand vous avez un choix à propos de quoi faire en premier, toujours aller de gauche à droite": l' a[b] est à la gauche de l' b=0, de sorte que l' a[b] s'exécute d'abord, résultant en a[1]. Puis l' b=0 qui se passe, et puis l'affectation de la valeur de a[1] arrive en dernier.

Choses à la gauche de se produire avant que les choses vers la droite. C'est la règle que vous cherchez. Parler de priorité et associativité des opérateurs est à la fois déroutant et hors de propos.

Les gens obtiennent ce trompent tout le temps, même les gens qui devraient savoir mieux. J'ai édité beaucoup trop de livres de programmation qui avaient déclaré que les règles de façon incorrecte, il n'est pas surprenant que beaucoup de gens ont complètement des croyances erronées au sujet de la relation entre la préséance/associativité, et l'ordre d'évaluation, à savoir que, en réalité, il n'existe pas de telle relation; ils sont indépendants.

Si ce sujet vous intéresse, voir mes articles sur le sujet pour en savoir plus:

http://blogs.msdn.com/b/ericlippert/archive/tags/precedence/

Ils sont sur le C#, mais la plupart de ce genre de choses s'applique aussi bien à Java.

32voto

Donal Fellows Points 56559

Eric Lippert est magistrale réponse est néanmoins pas correctement utile, parce qu'elle parle une langue différente. C'est de Java, où le Langage Java Spécification est la description exacte de la sémantique. En particulier, §15.26.1 est pertinente parce que le décrit l'ordre d'évaluation pour l' = opérateur (nous savons tous qu'il est en droit associatif, oui?). C'est la coupe vers le bas un peu pour les bits qui nous intéressent dans cette question:

Si la gauche opérande expression est un tableau de l'expression (§15.13), de nombreuses étapes sont nécessaires:

  • Tout d'abord, le tableau de référence de la sous-expression de la gauche opérande d'accès au tableau de l'expression est évaluée. Si cette évaluation se termine brusquement, alors l'expression d'affectation se termine brusquement pour la même raison; l'indice sous-expression (de la gauche opérande d'accès au tableau de l'expression) et la partie droite de l'opérande ne sont pas évalués et aucune affectation ne se produit.
  • Sinon, l'indice de la sous-expression de la gauche opérande d'accès au tableau de l'expression est évaluée. Si cette évaluation se termine brusquement, alors l'expression d'affectation se termine brusquement pour la même raison, et la partie droite de l'opérande n'est pas évalué et aucune affectation ne se produit.
  • Sinon, la partie droite de l'opérande est évaluée. Si cette évaluation se termine brusquement, alors l'expression d'affectation se termine brusquement pour la même raison et aucune affectation ne se produit.

[... il passe ensuite à décrire la signification réelle de la mission elle-même, que l'on peut ignorer ici par souci de concision ...]

En bref, Java est très étroitement définies ordre d'évaluation qui est à peu près exactement à gauche-à-droite dans les arguments de n'importe quel opérateur ou un appel de méthode. Tableau des affectations sont l'un des cas plus complexes, mais même là c'est encore L2R. (JLS ne vous recommandons de ne pas écrire du code qui a besoin de ces sortes de complexes contraintes sémantiques, et moi de même: vous pouvez obtenir plus de suffisamment de mal avec juste une assignation par l'énoncé!)

Le C et le C++ sont certainement différents de Java dans ce domaine: leur langue définitions de quitter ordre d'évaluation undefined délibérément pour permettre à plus d'optimisations. C# est comme Java apparemment, mais je ne sais pas sa littérature assez bien pour être en mesure de signaler à la définition formelle. (Cela varie vraiment en langue mais, Ruby est strictement L2R, comme Tcl - mais qui manque d'un opérateur d'affectation en soi, pour des raisons qui ne sont pas pertinentes en l'espèce - et Python est L2R mais R2L dans le respect de la cession, que je trouve étrange, mais là vous allez.)

1voto

JVerstry Points 12414

Votre code est équivalent à:

int[] a = {4,4};
int b = 1;
c = b;
b = 0;
a[c] = b;

ce qui explique le résultat.

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