Pergunta

Para minha surpresa, descobre-se que o seguinte código irá compilar, mesmo sem avisos:

public void test()
{
    int value = 2000000000;
    long increment = 1000000000;
    value += increment;
}

Considerando que este dá um erro em tempo de compilação, como seria de esperar:

public void test()
{
    int value = 2000000000;
    long increment = 1000000000;
    value = value + increment;
}

Eu verifiquei-lo e, de fato, o JLS (seção 15.26.2) tem isto a dizer:

Um composto de atribuição de expressão da forma E1 op = E2 é equivalente a E1 = (T) ((E1) op (E2)), onde T é o tipo de E1, exceto que E1 é avaliada apenas uma vez.

Isto parece ridículo para mim.Por que eles sentem a necessidade de explicitamente aqui?Parece que a conversão automática de tipo teria manipulado o alargamento de qualquer maneira, e automaticamente estreitamento como este é praticamente garantido para resultar em excesso de número inteiro.

Foi útil?

Solução

Aqui é uma explicação:

Quando você fizer uma atribuição (o primeiro trecho de código), java impõe a verificação de tipo, porque o LHS e RHS pode muito bem ser independentes uns dos outros.

Mas o composto-operador é mais como um incremental operador.A += modifica o valor da variável envolvidos, em vez de atribuir um novo valor para a variável.Quando você modificar um byte, você espera que um byte como o resultado.Para tornar a vida mais fácil, java está implícita uma conversão de tipo para composto-operadores, pois eles são modificadores.

Outras dicas

O composto operadores de atribuição são especificados por JLS (15.26.2) como segue:

"Um composto de atribuição de expressão da forma E1 op= E2 é equivalente a

      E1 = (T)((E1) op (E2))`, 

onde T é o tipo de E1, exceto que E1 é avaliado apenas uma vez."

Neste caso, E1 é do tipo int E2 é do tipo long, e op é +.Então, isso é equivalente a:

value = (int)(value + increment);

A adição de uma int e um long dá um long que é então convertido novamente para um int antes de atribuição.Que está tudo bem, portanto, nenhum erro de compilação.

A diferença entre esta e a atribuição simples (i.e. value = value + increment;), é que a simples atribuição de não ter um typecast.


OK, então por eles definem-lo desta maneira?

Eu acho que a razão é fazer com que exemplos como este trabalho:

    byte b = ...
    b += 1;

Sem o typecast, b += 1 seria um erro de compilação e você precisa escrevê-lo como:

    b += (byte) 1;

Este link tem analisado o problema que você trouxe para cima.

Comportamento variável para a possível perda de precisão

Para evitar surpresas desagradáveis, não o uso de compostos de operadores de atribuição em variáveis do tipo byte, short, ou char.Quando usando de atribuição composto operadores de variáveis do tipo int, certifique-se de que a expressão no do lado direito, não é do tipo long, float ou double.Quando utilizar o composto operadores de atribuição em variáveis de tipo float, certifique-se de que a expressão no lado direito, que não é do tipo casal.Estas regras são suficientes para impedir que o compilador gerar perigoso estreitamento lança.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top