example - my icon java
¿Cuáles son las reglas para el orden de evaluación en Java? (6)
Considere otro ejemplo más detallado a continuación.
Como regla general general:
Lo mejor es tener una tabla del orden de las reglas de precedencia y asociatividad disponible para leer al resolver estas preguntas, por ejemplo, http://introcs.cs.princeton.edu/java/11precedence/
Aquí hay un buen ejemplo:
System.out.println(3+100/10*2-13);
Pregunta: ¿Cuál es el resultado de la línea anterior?
Respuesta: Aplicar las Reglas de Precedencia y Asociatividad
Paso 1: De acuerdo con las reglas de precedencia: / y * los operadores tienen prioridad sobre los operadores + -. Por lo tanto, el punto de partida para ejecutar esta ecuación se reducirá a:
100/10*2
Paso 2: De acuerdo con las reglas y la precedencia: / y * son iguales en precedencia.
Como los operadores / y * tienen la misma precedencia, necesitamos ver la asociatividad entre esos operadores.
De acuerdo con las REGLAS DE ASOCIATIVIDAD de estos dos operadores particulares, comenzamos a ejecutar la ecuación de IZQUIERDA A DERECHA, es decir, 100/10 se ejecuta primero:
100/10*2
=100/10
=10*2
=20
Paso 3: la ecuación ahora está en el siguiente estado de ejecución:
=3+20-13
Según las reglas y la precedencia: + y - son iguales en precedencia.
Ahora necesitamos ver la asociatividad entre los operadores + y - operadores. De acuerdo con la asociatividad de estos dos operadores particulares, comenzamos a ejecutar la ecuación de IZQUIERDA a DERECHA, es decir, 3 + 20 se ejecuta primero:
=3+20
=23
=23-13
=10
10 es el resultado correcto cuando se compila
Nuevamente, es importante tener una tabla de las Reglas de Orden de Precedencia y Asociatividad con usted cuando resuelva estas preguntas, por ejemplo, http://introcs.cs.princeton.edu/java/11precedence/
Estoy leyendo algunos textos de Java y obtuve el siguiente código:
int[] a = {4,4};
int b = 1;
a[b] = b = 0;
En el texto, el autor no dio una explicación clara y el efecto de la última línea es: a[1] = 0;
No estoy tan seguro de entender: ¿cómo sucedió la evaluación?
La respuesta magistral de Eric Lippert no es, sin embargo, útil porque está hablando de un idioma diferente. Esto es Java, donde la Especificación del lenguaje Java es la descripción definitiva de la semántica. En particular, §15.26.1 es relevante porque describe el orden de evaluación para el operador =
(todos sabemos que es correcto-asociativo, ¿no?). Reducirlo un poco a las partes que nos interesan en esta pregunta:
Si la expresión del operando de la izquierda es una expresión de acceso a la matriz ( §15.13 ), entonces se requieren muchos pasos:
- En primer lugar, se evalúa la subexpresión de referencia de matriz de la expresión de acceso a la matriz de operandos de la izquierda. Si esta evaluación finaliza abruptamente, la expresión de asignación se completa abruptamente por la misma razón; la subexpresión de índice (de la expresión de acceso a la matriz de operandos de la izquierda) y el operando de la derecha no se evalúan y no se produce ninguna asignación.
- De lo contrario, se evalúa la subexpresión de índice de la expresión de acceso a la matriz de operandos de la izquierda. Si esta evaluación finaliza abruptamente, la expresión de asignación se completa abruptamente por la misma razón y el operando de la derecha no se evalúa y no se realiza ninguna asignación.
- De lo contrario, se evalúa el operando de la derecha. Si esta evaluación finaliza abruptamente, la expresión de asignación se completa abruptamente por el mismo motivo y no se produce ninguna asignación.
[... luego continúa describiendo el significado real de la tarea en sí, que podemos ignorar aquí para abreviar ...]
En resumen, Java tiene un orden de evaluación muy definido que es casi exactamente de izquierda a derecha dentro de los argumentos de cualquier operador o llamada de método. Las asignaciones de matriz son uno de los casos más complejos, pero incluso allí sigue siendo L2R. (El JLS recomienda que no se escriba el código que necesita este tipo de restricciones semánticas complejas , y yo también: ¡usted puede tener problemas más que suficientes con una sola asignación por declaración!)
C y C ++ son definitivamente diferentes a Java en esta área: sus definiciones de lenguaje dejan el orden de evaluación indefinido deliberadamente para permitir más optimizaciones. C # es aparentemente como Java, pero no conozco su literatura lo suficientemente bien como para poder señalar la definición formal. (Sin embargo, esto realmente varía según el idioma, Ruby es estrictamente L2R, como lo es Tcl -aunque eso carece de un operador de asignación por sí mismo por razones que no son relevantes aquí- y Python es L2R pero R2L con respecto a la asignación , lo cual me parece extraño pero .)
Permítanme decir esto muy claramente, porque las personas no entienden esto todo el tiempo:
El orden de evaluación de las subexpresiones es independiente tanto de la asociatividad como de la precedencia . La asociatividad y la precedencia determinan en qué orden se ejecutan los operadores pero no determinan en qué orden se evalúan las subexpresiones . Su pregunta es sobre el orden en que se evalúan las subexpresiones .
Considera A() + B() + C() * D()
. La multiplicación es una precedencia más alta que la suma, y la suma es asociativa a la izquierda, por lo que esto es equivalente a (A() + B()) + (C() * D())
Pero saber eso solo te dice que la primera suma ocurrirá antes de la segunda adición, y que la multiplicación ocurrirá antes de la segunda adición. ¡No le dice en qué orden serán llamados A (), B (), C () y D ()! (Tampoco le dice si la multiplicación ocurre antes o después de la primera suma). Sería perfectamente posible obedecer las reglas de precedencia y asociatividad compilando esto como:
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
Todas las reglas de precedencia y asociatividad se siguen allí: la primera suma ocurre antes de la segunda suma, y la multiplicación ocurre antes de la segunda suma. Claramente podemos hacer las llamadas a A (), B (), C () y D () en cualquier orden y aún obedecer las reglas de precedencia y asociatividad.
Necesitamos una regla no relacionada con las reglas de precedencia y asociatividad para explicar el orden en que se evalúan las subexpresiones. La regla relevante en Java (y C #) es "las subexpresiones se evalúan de izquierda a derecha". Como A () aparece a la izquierda de C (), A () se evalúa primero, independientemente del hecho de que C () esté involucrado en una multiplicación y A () esté involucrado solo en una suma.
Entonces ahora tienes suficiente información para responder tu pregunta. En a[b] = b = 0
las reglas de asociatividad dicen que esto es a[b] = (b = 0);
¡pero eso no significa que b=0
ejecuta primero! Las reglas de precedencia dicen que la indexación es una prioridad mayor que la asignación, pero eso no significa que el indexador se ejecute antes que la asignación más a la derecha .
Las reglas de precedencia y asociatividad imponen las restricciones que:
- La operación del indexador debe ejecutarse antes de la operación asociada a la operación de asignación de la mano izquierda
- La operación asociada a la operación de asignación de la mano derecha debe ejecutarse antes que la asociada a la operación de asignación de la mano izquierda.
La precedencia y la asociatividad solo nos dicen que la asignación de cero a b
debe ocurrir antes de la asignación a a[b]
. La precedencia y la asociatividad no dicen nada acerca de si a[b]
se evalúa antes o después de b=0
.
De nuevo, esto es exactamente lo mismo que: A()[B()] = C()
- Todo lo que sabemos es que la indexación debe ocurrir antes de la asignación. No sabemos si A (), B () o C () se ejecutan primero en función de la precedencia y la asociatividad . Necesitamos otra regla para decirnos eso.
La regla es, nuevamente, "cuando tienes que elegir primero qué hacer, siempre ve de izquierda a derecha": a[b]
está a la izquierda de b=0
, por lo que a[b]
ejecuta primero , lo que resulta en a[1]
. Entonces ocurre b=0
, y luego la asignación del valor a a[1]
ocurre la última vez.
Las cosas a la izquierda suceden antes que las cosas a la derecha. Esa es la regla que estás buscando. Hablar de precedencia y asociatividad es confuso e irrelevante.
La gente se equivoca todo el tiempo todo el tiempo , incluso personas que deberían saberlo mejor. He editado demasiados libros de programación que establecieron las reglas incorrectamente, por lo que no sorprende que mucha gente tenga creencias completamente incorrectas sobre la relación entre precedencia / asociatividad y orden de evaluación, es decir, que en realidad no existe tal relación ; ellos son independientes
Si este tema le interesa, consulte mis artículos sobre el tema para leer más:
http://blogs.msdn.com/b/ericlippert/archive/tags/precedence/
Son acerca de C #, pero la mayoría de estas cosas se aplica igualmente bien a Java.
Tu código es equivalente a:
int[] a = {4,4};
int b = 1;
c = b;
b = 0;
a[c] = b;
que explica el resultado
a[b] = b = 0;
1) el operador de indexación de arrays tiene mayor precedencia que el operador de asignación (ver esta respuesta ):
(a[b]) = b = 0;
2) De acuerdo con 15.26. Asignación de operadores de JLS
Hay 12 operadores de asignación; todos son sintácticamente correctos (se agrupan de derecha a izquierda). Por lo tanto, a = b = c significa a = (b = c), que asigna el valor de c a b y luego asigna el valor de b a a.
(a[b]) = (b=0);
3) De acuerdo con 15.7. Orden de evaluación de JLS
El lenguaje de programación Java garantiza que los operandos de los operadores parecen evaluarse en un orden de evaluación específico, es decir, de izquierda a derecha.
y
El operando de la izquierda de un operador binario parece estar completamente evaluado antes de que se evalúe cualquier parte del operando de la derecha.
Asi que:
a) (a[b])
evaluado primero a a[1]
b) luego (b=0)
evaluado a 0
c) (a[1] = 0)
evaluado en último lugar
public class TestClass{
public static void main(String args[] ){
int i = 0 ;
int[] iA = {10, 20} ;
iA[i] = i = 30 ;
System.out.println(""+ iA[ 0 ] + " " + iA[ 1 ] + " "+i) ;
} }
Imprimirá 30 20 30
La declaración iA [i] = i = 30; se procesará de la siguiente manera:
iA [i] = i = 30; => iA [0] = i = 30; => i = 30; iA [0] = i; => iA [0] = 30;
Esto es lo que dice JLS sobre esto:
1 Evaluar primero el operando de la mano izquierda
2 Evaluar los operandos antes de la operación
3 La evaluación respeta los paréntesis y la precedencia
4 listas de argumentos se evalúan de izquierda a derecha
Para matrices: Primero, las expresiones de dimensión se evalúan de izquierda a derecha. Si alguna de las evaluaciones de expresión se completa abruptamente, las expresiones a la derecha de la misma no se evalúan.