Precedência de operadores 1

Estou estudando para a certificação de programador, e tenho algumas dúvidas sobre precedência, talvez alguém possa me ajudar.

Primeiramente, segundo uma tabela no tutorial da própria Sun, os operadores de pós-incremento têm precedência sobre os de pré-incremento. Segundo a maioria das fontes na internet esses operadores são avaliados da direita para a esquerda. No entanto, até onde eu fui capaz de testar, ambos operadores têm a mesma precedência e são avaliados da esquerda para a direita! Na prática:

public class Test {
    public static void main (String[] argumentos) {
        int a = 5;
        a = ++a + a++ * ++a;
        //   1     2     3
        System.out.println(a);
    }
}

O resultado é 54 (usando o J2SE 1.5 da Sun). Isso quer dizer que o 1 (++a) foi avaliado primeiro, resultando em 6 (e incrementando a variavel a para 6), em seguida o 2 (a++) foi avaliado, resultando em 6 (e incrementando a variável a para 7), em seguida o 3 foi avaliado, resultando em 8 (e incrementando a variável a para 8). Após a avaliação desses argumentos, é feita a multiplicação do resultado de 2 e 3 (6 * 8), resultando em 48, que em seguida é somado com 1 (6 + 48), resultando em 54.

Se o operador de pós-incremento (2) fosse avaliado primeiro, ele retornaria 5, e os outros dois (1 e 3) retornariam 7 e 8 (isso se forem avaliados da esquerda para a direita), o que resultaria em 47. Se a ordem de avaliação fosse da direita para a esquerda o resultado seria 43.

Meu raciocínio está correto? O tutorial da Sun está errado?

Olá,
java, neste ponto, age um pouco diferente do C.

No C, os operandos somente são atualizados após os chamados “sequence points”, que são os finais de instruções (statement), operadores lógicos ( &, &&, |, ||) ou a vírgula, operador de separação (como em a = a++, b = a)

No java, o incremento dos operadores de incremento (!) ocorre após a avaliação de cada expressão, daí, temos:

++a => 1 + 5 => a = 6 - pegamos 6

a++ => pegamos 6; ++ => 6 + 1 => a = 7

++a pegamos 1 + 7 = 8!

Parece lógico!!?? :o/

Acho que meu raciocínio está correto então.

Mas aqui vem mais uma dúvida (veja o código a seguir): se os parenteses têm precedência maior, o a++ não deveria ser avaliado primeiro, resultando em 47?

public class Test {
    public static void main (String[] argumentos) {
        int a = 5;
        a = ++a + (a++) * ++a;
        //   1     2     3
        System.out.println(a);
    }
}

Isso não acontece, o resultado continua sendo sendo 54. Por que?

Os parenteses apenas alteram a prescedência quando houver mais de um operador ENTRE os parenteses!

Em (a++) os parenteses apenas garantem que o ++ ocorrerá primeiro…, mas antes de quem, se não tem mais nada entre os parenteses?

A idéia dos parênteses funciona em situações como

1 + 2 * 3 ==> 1 + 6 ( da matemática do ensino fundamental)
(1 + 2) * 3 ==> 3 * 3

No seu exemplo, fazer

a = ++a + (a++) * ++a;

ou

a = (++a) + (a++) * (++a);

ou a = ++a + a++ * ++a;

que diferença faria?

Caro spier, obrigado pelas respostas e pela sua paciência.

Fiz alguns testes baseados na sua resposta. Foi possível concluir que: se dentro dos parenteses houver apenas uma variável, com ou sem operador unário (++, --, ou ~), os parenteses são ignorados. Só pra confirmar:

public class Test {
    public static void main (String[] argumentos) {
        int a = 5;
        a = a++ + (a);
        System.out.println(a);
    }
}

Isso resulta em 11, ou seja, a variável a entre parenteses não é avaliada primeiro. Se os parenteses tivessem efeito, o resultado seria 10.

Outro exemplo, dessa vez com outro operador unário:
(Só pra lembrar: o inverso (~) de -1 é 0)

public class Test {
    public static void main (String[] argumentos) {
        int a = -1;
        a = a++ + (~a);
        System.out.println(a);
    }
}

Os parenteses também são ignorados, resultando em -2 e não em 0.

No entanto, nem sempre quando há um operador binário (que tem dois operandos) entre parenteses os mesmos têm efeito:

public class Test {
    public static void main (String[] argumentos) {
        int a = 5;
        a = a + (a = 1);
        System.out.println(a);
    }
}

Isso resulta em 6 e não em 2. No entanto, os parênteses não são totalmente ignorados, pois se forem removidos, o código não irá compilar. Uma vez que a + a é avaliado antes (uma vez que + tem maior precedência que =) e resulta em um valor, ao qual não se pode atribuir outro valor (Seria o mesmo que fazer: 10 = 1).

Não tenho certeza se esse é o único caso, preciso investigar melhor. Se alguém puder me explicar por que o código acima se comporta dessa forma eu agradeceria muito.

Ói Tyler,

Vamos ver se posso ajudar!

int a = 5;
a = a + (a = 1);

Os operandos são avaliados primeiro, e da esquerda para a direita, então
teremos:

a = 5 + (a = 1);

agora o literal “1” será atribuído ao “a” por força dos parênteses, ficando:

a = 5 + 1;

finalizando, temos:

a = 6;

ok?

Robson

Amigos…

encontrei um exercício q pode ajudar a sanar essas questões…

http://www.danchisholm.net/july21/mybook/chapter3/exam1.html

Analisem os testes 17, 18 e 23.

Seguem as respostas do próprio autor:

Questão 17
The expression can be simplified as follows: j = 2 + 2 + -3 + 3 = 4. The original expression is as follows: j = ++i + i++ + -i + i++. Simplification step one. Evaluate the unary expressions from left to right: j = 2 + 2 + -3 + 3. Step two. Complete the evaluation of the simplified expression: j = 4.

Questão 18
The expression can be simplified as follows: j = 1 + (2 * 3) + 4 = 11. The original expression is as follows: j = m(i++) + m(i++) * m(i++) + m(i++). The method, m, prints and then returns the value of the parameter, so the original expression is equivalent to the following: j = i++ + i++ * i++ + i++. Step one. Work through the expression from left to right to evaluate the unary expressions: j = 1 + 2 * 3 + 4. Step two. Add parentheses to indicate operator precedence: j = 1 + (2 * 3) + 4. Step three. Work through the simplified expression: j = 1 + 6 + 4 = 11. Step four. Evaluate the expression that is the argument of the print method: j % 5 = 11 % 5 = 1.

Questão 23
The two statements, int a=1 followed by a += ++a + a++, can be rewritten as the single statement, a=(int)((1)+(++a + a++)). Further evaluation produces a=(int)((1)+(2 + 2)). Generally speaking, a compound assignment expression of the form E1 op= E2 can be rewritten as E1=(T)((E1)op(E2)) where T is the type of E1.

Nessa página há exercícios muito bons para quem vai fazer a certificação!!

Espero ter ajudado… :wink:

Abraço.