Precedência de operadores 1

6 respostas
T

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?

6 Respostas

S

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/

T

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?

S

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?

T

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.

R

Ó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

T

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.

Criado 4 de dezembro de 2004
Ultima resposta 5 de jan. de 2005
Respostas 6
Participantes 4