Alguma idéia de por que preciso converter um literal inteiro para (int) aqui?


122

No exemplo a seguir

int i = -128;
Integer i2 = (Integer) i; // compiles

Integer i3 = (Integer) -128; /*** Doesn't compile ***/

Integer i4 = (Integer) (int) -128; // compiles
Integer i4 = -128; // compiles
Integer i5 = (int) -128; // compiles
Integer i6 = (Integer) (-128); // compiles
Integer i7 = (Integer) 0-128; // compiles

Eu não pode lançar -128com (Integer)mas pode lançar (int) -128.

Eu sempre pensei que -128era do inttipo e lançá-lo com (int)deve ser redundante.

O erro na linha com i3é

cannot find symbol variable Integer

Eu tentei isso com o Java 6 atualização 29 e o Java 7 atualização 1.

Edição: Você obtém o mesmo comportamento com em +128vez de -128. Parece haver confusão entre operadores unários e binários.


5
qual é o seu compilador? Integer i = -128;isso deve compilar, no entanto.
bestsss 26/10/11

estranho, Integer i3 = (Integer) (-128);cumpre.
Eng.Fouad 26/10/11

2
@ Eng.Fouad, Peter, símbolos unários (+ -) têm associatividade da direita para a esquerda e mais, menos são da esquerda para a direita. O efeito de -128 seria o mesmo que +128 e colocar 0 na frente deve ser corrigido, ou seja, 0-128 ou 0 + 128. (não posso testar o atm, mas aposto que sim)
bestsss 26/10/11

Boa pergunta! Pessoalmente, gostaria de ver uma referência JLS para a resolução de operadores unários / binários e quando uma conversão é tratada como uma expressão. Caso contrário, pode ser possível que outros compiladores não considerem isso um erro!
Bringer128

1
Também para sua informação, o erro que recebo no meu IDE é Expression expectedonde Integerestá.
Bringer128

Respostas:


151

O compilador tenta subtrair 128de em (Integer)vez de converter -128para Integer. Adicione ()para corrigi-lo

Integer i3 = (Integer) -128; // doesn't compile
Integer i3 = (Integer) (-128); // compiles

De acordo com BoltClock nos comentários, o elenco intfunciona como pretendido, porque é uma palavra reservada e, portanto, não pode ser interpretada como um identificador, o que faz sentido para mim.

E Bringer128 encontrou a Referência JLS 15.16 .

 Expressão:
    (PrimitiveType Dims opt ) UnaryExpression
    (ReferenceType) UnaryExpressionNotPlusMinus

Como você pode ver, a conversão para um tipo primitivo requer alguma UnaryExpression, enquanto a conversão para um tipo de referência requer a UnaryExpressionNotPlusMinus. Eles são definidos antes do CastExpression no JLS 15.15 .


31
Eu acho que é porque inté uma palavra-chave em Java, mas Integernão é. Como inté uma palavra-chave, não é possível usá-la como identificador de uma variável ou classe, deixando a única possibilidade de que seja uma conversão de tipo. Isso explicaria isso.
BoltClock

@BoltClock Incorporou seu comentário na resposta.
Jens Schauder

3
Para tornar essa uma resposta ainda mais estelar, você deseja adicionar meu link ao JLS?
precisa saber é o seguinte

3
Uma ruga interessante (para mim) sobre esse problema é como resolvemos o problema análogo em C #, que também tem uma ambiguidade na gramática entre "expressão entre parênteses como um operando para operador de subtração binária" e "operador de conversão onde o operando certo do cast é uma expressão negativa unária ". Consulte a seção 7.7.6 da especificação C # para obter uma descrição detalhada das heurísticas que usamos para tentar ser esperto ao resolver a ambiguidade.
Eric Lippert

1
@ BillK Por que você diz isso? A especificação C # não se refere à sobrecarga do operador na seção 7.7.6, portanto não foi um problema para eles.
Bringer128

48

Encontrei a referência JLS. 15.16 .

 Expressão:
    (PrimitiveType Dims opt ) UnaryExpression
    (ReferenceType) UnaryExpressionNotPlusMinus

Como você pode ver, a conversão para um tipo primitivo requer alguma UnaryExpression, enquanto a conversão para um tipo de referência requer a UnaryExpressionNotPlusMinus. Eles são definidos antes do CastExpression no JLS 15.15 .

Você precisa alterar a conversão para um tipo primitivo:

... (int) -128;

Ou você pode alterar a expressão à direita do elenco para uma expressão unária não mais-menos:

... (Integer) (-128);  // Either
... (Integer) 0 - 128; // Or

12

O compilador interpreta o -operador como menos de dois argumentos, ou seja, está tentando subtrair 128 de outro número chamado Integer, mas não há tal variável no escopo.

Isso compila:

Integer i3 = (Integer) (-128)

Você pode adicionar um comentário sobre o motivo da (int)diferença.
Peter Peterrey

1
É devido ao autoboxing, não?
Brian Roach

9

Isso pode ter a ver com a análise de sintaxe. Notar que

Integer i4 = (Integer) (-128); 

funciona muito bem.

Em geral, você não deve converter na classe Integer. Isso envolve algo chamado boxe automático e pode causar alguns erros sutis no seu código. O método preferido de fazer o que você quer é:

Integer i6 = Integer.valueOf(-128)

1
convertido para Inteiro é exatamente açúcar sintético para valor de.
bestsss 26/10/11

4
sim, mas às vezes o açúcar sintético falha de maneiras sutis. Eu tive algumas dificuldades para rastrear exceções de ponteiro nulo em aplicativos grandes devido ao boxe automático. Chegamos ao ponto de tratar o boxe automático como erros, a fim de evitar dores de cabeça no futuro. A magia é boa, mas quando falha, a cabeça machuca. Acho melhor ser explícito e evitar as dores de cabeça.
Krystian Cybulski

NPE são b1tch w / outboxing, é verdade. Casos esp como for (int i in Collection<Integer>)b / c o NPE estão em local absolutamente inesperado. Na verdade, eu não uso Integer w / autoboxing, pois o intervalo de cache é pequeno (embora possa ser aumentado com a opção XX), mas tenho uma classe chamada IntegerProvider (desde 1.1) para fazer as mesmas coisas. Usando Map (qualquer um dos java.util) Inteiro-> Qualquer coisa geralmente é um problema de desempenho, a menos que seja usada para casos triviais e quase sempre haja uma solução melhor.
bestsss 26/10/11

A conversão de int para Inteiro nunca pode causar erros, exceto o estouro de heap, talvez. O inverso não é verdade, no entanto.
Ingo

@ MattBall, eu não entendo direito, o açúcar sintético é amplamente utilizado: eggcorns.lascribe.net/forum/viewtopic.php?id=4400 e o sintético soa melhor para mim.
bestsss 26/10/11

9

Ele está analisando como Integer <minus operator> 128e não encontrando a variável Integer. Você precisará agrupar os -128colchetes:

Integer i3 = (Integer) (-128);  // compiles

Eu atribui +1 a todas as outras respostas, porque elas também estão corretas :)
Bohemian

7
Integer i3 = (Integer) (-128);

O problema é que o -compilador o vê como um operador.


6

A linha 3 é interpretada como se você estivesse tentando deduzir 128 da expressão entre parênteses e a expressão entre parênteses não é e expressão do tipo int (trata o operador '-' como um operador '-'). Se você alterar a expressão para:

Integer i3 = (Integer) (-128);

então o compilador entenderá que '-' é o menos unário que indica um número inteiro negativo.


3

O compilador C # tem o mesmo comportamento. Ele dá uma dica melhor do porquê de não conseguir compilar:

Para converter um valor negativo, você deve colocar o valor entre parênteses

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.