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?
La confusion ci-dessous sur ce qui se passe signifie que vous ne devriez jamais le faire, comme beaucoup de gens auront à réfléchir sur ce qu'il fait réellement, au lieu d'être évident.
La bonne réponse à une question de ce genre est "ne fais pas ça!" La cession devrait être traitée comme une déclaration; l'utilisation de cession comme une expression qui retourne une valeur devrait porter une erreur du compilateur, ou un avertissement à tout le moins. Ne pas le faire.
La bonne réponse à une question de ce genre est "ne fais pas ça!" La cession devrait être traitée comme une déclaration; l'utilisation de cession comme une expression qui retourne une valeur devrait porter une erreur du compilateur, ou un avertissement à tout le moins. Ne pas le faire.
OriginalL'auteur ipkiss | 2011-07-23
Vous devez vous connecter pour publier un commentaire.
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 la priorité. L'associativité et la priorité de déterminer dans quel ordre les opérateurs sont exécutés, mais ne pas de déterminer dans quel ordre les sous-expressions sont évalués. Votre question est sur l'ordre dans lequel sous-expressions sont évalués.
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 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 par la compilation de ce que: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 de l'ordre et de toujours obéir aux règles de priorité et associativité des!
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. Dans
a[b] = b = 0
les règles d'associativité dire que c'esta[b] = (b = 0);
mais cela ne signifie pas que lab=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.(Mise à JOUR: Une version antérieure de cette réponse avait quelques petites et pratiquement sans importance omissions dans la section qui suit, que j'ai corrigée. J'ai également écrit un article de blog décrivant les raisons pour lesquelles ces règles sont sensées en Java et C# ici: https://ericlippert.com/2019/01/18/indexer-error-cases/)
Priorité et associativité des opérateurs de nous dire que la cession de zéro à
b
doit arriver avant l'affectation àa[b]
, parce que la cession de zéro calcule la valeur est affectée à l'opération d'indexation. Priorité et associativité des seul à ne rien dire au sujet de savoir si laa[b]
est évaluée avant ou après lab=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 basé sur la priorité et l'associativité. Nous avons besoin d'une règle pour nous dire qu'.La règle est, de nouveau, "quand vous avez un choix à propos de quoi faire en premier, toujours aller de gauche à droite". Cependant, il est intéressant de ride dans ce scénario spécifique. Est l'effet secondaire de la levée d'une exception provoquée par une nulle de collecte ou en dehors de la plage de l'index considéré comme faisant partie du calcul de la partie gauche de l'affectation ou de la partie du calcul de l'attribution de lui-même? Java choisit cette dernière. (Bien sûr, c'est une distinction que les choses ne si le code est déjà mal, parce que le code est correct de ne pas déréférencer null ou de passer un mauvais indice en premier lieu.)
Donc ce qui se passe?
a[b]
est à la gauche de lab=0
, de sorte que lea[b]
s'exécute première, résultant ena[1]
. Toutefois, la vérification de la validité de cette opération d'indexation est retardée.b=0
qui se passe.a
est valide eta[1]
est dans la gamme qui se passea[1]
arrive en dernier.Donc, bien que dans ce spécifiques cas il y a quelques subtilités à prendre en compte pour les rares cas d'erreur ne devrait pas se produire dans le code est correct, en premier lieu, en général, vous pouvez raison: 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 à obtenir ce genre de choses mal tout le temps, même les gens qui devraient savoir mieux. J'ai édité beaucoup trop de les 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.
Suis-je correct que le C++ n'est pas le garantir? Qu'en Python?
C++ ne garantit rien sur l'ordre de l'évaluation, et ne l'a jamais fait. (Ni C.) Python garanties strictement par ordre de priorité; à la différence de tout le reste, l'affectation est R2L.
pour moi, vous le son de tout confondre. Et les règles de priorité seulement implique que les enfants doivent être évalués avant que les parents. Mais ils ne disent rien sur l'ordre dans lequel les enfants sont évalués. Java et C# a choisi de gauche à droite, le C et le C++ a choisi un comportement indéfini.
OK, pensez à: M(A() + B () C() * D(), E() + F()). Votre souhait est pour les sous-expressions à être évalués dans quel ordre? Doit C() et D() sera évaluée avant A(), B(), E() et F() parce que la multiplication est une priorité plus élevée que l'addition? Il est facile de dire que "de toute évidence" l'ordre doit être différent. Venir avec une règle qui couvre tous les cas est un peu plus difficile. Les concepteurs de C# et Java choisi un simple, facile à expliquer la règle: "allez à gauche-à-droite". Qu'est-ce que votre proposition de remplacement pour elle, et pourquoi croyez-vous que votre règle est le meilleur?
OriginalL'auteur Eric Lippert
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 la
=
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:[... 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 recommande que vous 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 soi pour des raisons qui ne sont pas pertinentes en l'espèce — et Python est L2R mais R2L dans le respect de l'affectation, que je trouve étrange, mais là vous allez.)
La règle de Java et C#) est "sous-expressions sont évaluées de gauche à droite" - me semble qu'il parle à la fois.
Un peu confus ici - cela fait-il de la réponse ci-dessus par Eric Lippert moins vrai, ou est-il juste de citer une référence spécifique, comme quoi il est vrai?
Eric réponse est vrai, mais comme je l'ai dit vous ne pouvez pas prendre un aperçu d'une langue dans ce domaine et de l'appliquer à un autre sans être prudent. Si j'ai cité la source définitive.
la chose étrange est, la droite est évaluée avant gauche de la variable est résolu; en
a[-1]=c
,c
est évaluée, avant de-1
est reconnu comme valide.OriginalL'auteur Donal Fellows
1) tableau d'indexation de l'opérateur a une priorité plus élevée, puis opérateur d'affectation (voir cette réponse):
2) Selon 15.26. Opérateurs d'affectation de JLS
3) Selon 15.7. Ordre d'évaluation des JLS
et
Donc:
a)
(a[b])
d'abord évaluée àa[1]
b) puis
(b=0)
évalué à0
c)
(a[1] = 0)
évaluée en dernierOriginalL'auteur bup
Votre code est équivalent à:
qui explique le résultat.
La réponse est parce que c'est ce qui se passe sous le capot considérant le code fourni dans la question. C'est la manière dont l'évaluation se passe.
Oui, je sais. Toujours pas de répondre à la question de l'OMI, qui est pourquoi c'est la manière dont l'évaluation se passe.
c'est la manière dont l'évaluation se passe? "n'est pas la question posée." comment l'évaluation est-il arrivé? " est la question posée.
Comment sont-ils pas l'équivalent? Le tableau de référence de la sous-expression de la main gauche opérande est l'opérande de gauche. Donc, en disant: "ne le plus à gauche d'abord", c'est exactement la même chose que de dire "faire le tableau de référence de la première". Si le Java spec auteurs ont choisi d'être inutilement verbeux et redondant dans l'explication de cette règle particulière, tant mieux pour eux; ce genre de chose est prête à confusion et devrait être plutôt plus que moins verbeux. Mais je ne vois pas comment mon concis caractérisation est sémantiquement différents de leurs prolixes de caractérisation.
OriginalL'auteur Jérôme Verstrynge
Envisager une autre plus en profondeur exemple ci-dessous.
Comme une Règle Générale:
Il est préférable d'avoir un tableau de l'Ordre des Règles de Priorité et d'Associativité disponible à la lecture, lors de la résolution de ces questions, par exemple http://introcs.cs.princeton.edu/java/11precedence/
Ici est un bon exemple:
Question: Quel est le résultat de la Ligne ci-dessus?
Réponse: Appliquer les Règles de Priorité et Associativité des
Étape 1: Selon les règles de préséance: /et * les opérateurs de prendre la priorité sur + - opérateurs. Par conséquent, le point de départ pour l'exécution de cette équation de la réduire à:
Étape 2: Selon les règles de priorité et d': /et * sont égaux dans l'ordre de priorité.
Que /et * l'égalité des opérateurs dans l'ordre de priorité, nous avons besoin de regarder l'associativité entre les opérateurs.
Selon les RÈGLES d'ASSOCIATIVITÉ de ces deux opérateurs,
nous avons commencer à exécuter l'équation de la GAUCHE VERS la DROITE c'est à dire 100/10 est exécuté en premier:
Étape 3: L'équation est maintenant dans l'état suivant de l'exécution:
Selon les règles de priorité et d': + et - sont égaux dans l'ordre de priorité.
Nous avons maintenant besoin de regarder l'associativité entre les opérateurs opérateurs + et -. Selon l'associativité de ces deux opérateurs,
nous avons commencer à exécuter l'équation de la GAUCHE vers la DROITE c'est à dire 3+20 est exécuté en premier:
10 est le bon de sortie lors de la compilation
Encore une fois, il est important d'avoir un tableau de l'Ordre des Règles de Priorité et d'Associativité avec vous lors de la résolution de ces questions, par exemple http://introcs.cs.princeton.edu/java/11precedence/
10 - 4 - 3
.Je soupçonne que cette erreur peut être causée par le fait qu'au-dessus de introcs.cs.princeton.edu/java/11precedence
+
est opérateur unaire (qui a droit à l'associativité gauche), mais additif + et - ont-tout comme multiplicatif * / % gauche à droite associativité.Bien repéré et modifié en conséquence, je vous remercie Pshemo
Cette réponse explique priorité et associativité des opérateurs, mais, comme Eric Lippert expliqué, la question est à propos de l'évaluation de l'ordre, ce qui est très différent. Comme une question de fait, ce n'est pas de répondre à la question.
OriginalL'auteur Mark Burleigh