O limite de int
é de -2147483648 a 2147483647.
Se eu inserir
int i = 2147483648;
o Eclipse solicitará um sublinhado vermelho em "2147483648".
Mas se eu fizer isso:
int i = 1024 * 1024 * 1024 * 1024;
compilará bem.
public class Test {
public static void main(String[] args) {
int i = 2147483648; // error
int j = 1024 * 1024 * 1024 * 1024; // no error
}
}
Talvez seja uma pergunta básica em Java, mas não tenho idéia por que a segunda variante não produz erros.
2147483648
: esse literal não faz sentido.Respostas:
Não há nada de errado com essa afirmação; você está apenas multiplicando 4 números e atribuindo-o a um int, acontece que existe um estouro. Isso é diferente de atribuir um único literal , que seria verificado nos limites em tempo de compilação.
É o literal fora dos limites que causa o erro, não a atribuição :
Por outro lado, um
long
literal compilaria bem:Observe que, de fato, o resultado ainda é calculado em tempo de compilação porque
1024 * 1024 * 1024 * 1024
é uma expressão constante :torna-se:
Observe que o resultado (
0
) é simplesmente carregado e armazenado, e nenhuma multiplicação ocorre.Do JLS §3.10.1 (obrigado ao @ChrisK por mencioná-lo nos comentários):
fonte
-1 + 1
, é inofensivo; mas1024^4
isso poderia deixar de lado as pessoas com resultados totalmente inesperados, longe do que eles esperariam ver. Eu acho que deveria haver pelo menos um aviso ou nota para o usuário, e não ignorá-lo silenciosamente.1024 * 1024 * 1024 * 1024
e2147483648
não tem o mesmo valor em Java.Na verdade,
2147483648
NÃO É UM VALOR (embora2147483648L
seja) em Java. O compilador literalmente não sabe o que é ou como usá-lo. Então, lamenta.1024
é um int válido em Java e um válidoint
multiplicado por outro válidoint
, é sempre um válidoint
. Mesmo que não seja o mesmo valor que você esperaria intuitivamente, porque o cálculo transbordará.Exemplo
Considere o seguinte exemplo de código:
Você esperaria que isso gerasse um erro de compilação? Torna-se um pouco mais escorregadio agora.
E se colocarmos um loop com 3 iterações e multiplicarmos no loop?
O compilador pode otimizar, mas não pode alterar o comportamento do programa enquanto o faz.
Algumas informações sobre como esse caso é realmente tratado:
Em Java e em muitas outras linguagens, os números inteiros consistem em um número fixo de bits. Cálculos que não cabem no número especificado de bits serão excedidos ; o cálculo é basicamente executado no módulo 2 ^ 32 em Java, após o qual o valor é convertido novamente em um número inteiro assinado .
Outros idiomas ou APIs usam um número dinâmico de bits (
BigInteger
em Java), geram uma exceção ou configuram o valor para um valor mágico, como não um número.fonte
2147483648
NÃO É MESMO VALOR (embora2147483648L
seja)", realmente consolidou o argumento que @arshajii estava tentando fazer.1024 * 1024 * 1024 * 1024
é tratado, eu realmente queria enfatizar que não é a mesma coisa que escrever2147473648
. Há muitas maneiras (e você listou algumas) de que um idioma possa lidar com ele. É razoavelmente separado e útil. Então eu vou deixar. Muitas informações se tornam cada vez mais necessárias quando você tem uma resposta de alto nível em uma pergunta popular.O comportamento que você sugere - isto é, a produção da mensagem de diagnóstico quando uma computação produz um valor maior que o maior valor que pode ser armazenado em um número inteiro - é um recurso . Para você usar qualquer recurso, o recurso deve ser pensado, considerado uma boa idéia, projetado, especificado, implementado, testado, documentado e enviado aos usuários.
Para Java, uma ou mais das coisas nessa lista não aconteceram e, portanto, você não possui o recurso. Não sei qual; você teria que perguntar a um designer Java.
Para C #, todas essas coisas aconteceram - cerca de catorze anos atrás agora - e, portanto, o programa correspondente em C # produziu um erro desde o C # 1.0.
fonte
Além da resposta de arshajii, quero mostrar mais uma coisa:
Não é a atribuição que causa o erro, mas simplesmente o uso do literal . Quando você tenta
você notará que também causa um erro de compilação, pois o lado direito ainda é um
int
literal e está fora do alcance.Portanto, operações com
int
-values (e isso inclui atribuições) podem transbordar sem um erro de compilação (e também sem um erro de tempo de execução), mas o compilador simplesmente não pode lidar com esses literais muito grandes.fonte
A: Porque não é um erro.
Antecedentes: A multiplicação
1024 * 1024 * 1024 * 1024
levará a um estouro. Um estouro é muitas vezes um erro. Diferentes linguagens de programação produzem comportamentos diferentes quando ocorrem estouros. Por exemplo, C e C ++ chamam isso de "comportamento indefinido" para números inteiros assinados, e o comportamento é definido como números inteiros não assinados (pegue o resultado matemático, adicioneUINT_MAX + 1
enquanto o resultado for negativo, subtraiaUINT_MAX + 1
enquanto o resultado for maior queUINT_MAX
).No caso de Java, se o resultado de uma operação com
int
valores não estiver no intervalo permitido, conceitualmente, o Java adiciona ou subtrai 2 ^ 32 até que o resultado esteja no intervalo permitido. Portanto, a declaração é completamente legal e não está errada. Simplesmente não produz o resultado que você esperava.Você certamente pode discutir se esse comportamento é útil e se o compilador deve lhe dar um aviso. Eu diria pessoalmente que um aviso seria muito útil, mas um erro estaria incorreto, pois é Java legal.
fonte