¿Alguna idea de por qué necesito emitir un literal entero a (int) aquí?

122

En el siguiente ejemplo

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

No puedo fundido -128con (Integer)pero puedo fundido (int) -128.

Siempre pensé que -128era de inttipo y lanzarlo (int)debería ser redundante.

El error en la línea con i3es

cannot find symbol variable Integer

Intenté esto con Java 6 actualización 29 y Java 7 actualización 1.

EDITAR: Obtiene el mismo comportamiento con en +128lugar de -128. Parece ser una confusión entre operadores unarios y binarios.

Peter Lawrey
fuente
55
¿Cuál es tu compilador? Integer i = -128;esto debería compilar, sin embargo.
bestsss
extraño, Integer i3 = (Integer) (-128);cumple sin embargo.
Eng.Fouad
2
@ Eng.Fouad, Peter, los símbolos unarios (+ -) tienen asociatividad de derecha a izquierda y más, menos se dejan de derecha a izquierda. El efecto de -128 sería el mismo que +128 y se debería corregir poner 0 al frente, es decir, 0-128 o 0 + 128. (atm prueba no puede pero apuesto a que lo hará)
bestsss
¡Buena pregunta! Personalmente, me gustaría ver una referencia de JLS para la resolución de operadores unarios / binarios y cuando un reparto se trata como una expresión. De lo contrario, ¡podría ser posible que otros compiladores no lo consideren un error!
Bringer128
1
También digo que el error que obtengo en mi IDE es Expression expecteddonde Integerestá.
Bringer128

Respuestas:

151

El compilador intenta restar 128de en (Integer)lugar de enviar -128a Integer. Agregar ()para arreglarlo

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

Según BoltClock en los comentarios, el elenco intfunciona según lo previsto, porque es una palabra reservada y, por lo tanto, no puede interpretarse como un identificador, lo que tiene sentido para mí.

Y Bringer128 encontró la referencia JLS 15.16 .

 CastExpression:
    (PrimitiveType Dims opta ) UnaryExpression
    (ReferenceType) UnaryExpressionNotPlusMinus

Como puede ver, la conversión a un tipo primitivo requiere cualquiera UnaryExpression, mientras que la conversión a un tipo de referencia requiere a UnaryExpressionNotPlusMinus. Estos se definen justo antes de CastExpression en JLS 15.15 .

Jens Schauder
fuente
31
Creo que es porque intes una palabra clave en Java, pero Integerno lo es. Dado que intes una palabra clave, no puede usarla como un identificador para una variable o una clase, dejando la única posibilidad que queda para que sea una conversión de texto. Eso lo explicaría.
BoltClock
@BoltClock incorporó su comentario en la respuesta.
Jens Schauder
3
Para que esta sea una respuesta aún más estelar, ¿desea agregar mi enlace al JLS?
Bringer128
3
Una arruga interesante (para mí) sobre este tema es cómo resolvemos el problema análogo en C #, que también tiene una ambigüedad en la gramática entre "expresión entre paréntesis como operador de operador de resta binaria" y "operador de conversión donde el operando correcto del emitir es una expresión menos unaria ". Consulte la sección 7.7.6 de la especificación de C # para obtener una descripción detallada de las heurísticas que usamos para tratar de ser inteligentes al resolver la ambigüedad.
Eric Lippert
1
@BillK ¿Por qué dices eso? La especificación de C # no se refiere a la sobrecarga del operador en la sección 7.7.6, por lo que no fue un problema para ellos.
Bringer128
48

Encontré la referencia de JLS. 15.16 .

 CastExpression:
    (PrimitiveType Dims opta ) UnaryExpression
    (ReferenceType) UnaryExpressionNotPlusMinus

Como puede ver, la conversión a un tipo primitivo requiere cualquiera UnaryExpression, mientras que la conversión a un tipo de referencia requiere a UnaryExpressionNotPlusMinus. Estos se definen justo antes de CastExpression en JLS 15.15 .

Debe cambiar el reparto a un tipo primitivo:

... (int) -128;

O puede cambiar la expresión a la derecha de la conversión a una expresión unaria no más-menos:

... (Integer) (-128);  // Either
... (Integer) 0 - 128; // Or
Bringer128
fuente
12

El compilador interpreta el -como el operador negativo de dos argumentos, es decir, está tratando de restar 128 de algún otro número nombrado Integer, pero no existe tal variable en el alcance.

Esto compila:

Integer i3 = (Integer) (-128)
Extremo de la barra
fuente
Puede agregar un comentario sobre por qué (int)hace la diferencia.
Peter Lawrey
1
Se debe al autoboxing, ¿no?
Brian Roach
9

Esto puede tener que ver con el análisis sintáctico. Darse cuenta de

Integer i4 = (Integer) (-128); 

funciona bien

En general, no debes lanzar a la clase Integer. Esto implica algo llamado auto-boxeo y puede causar algunos errores sutiles en su código. El método preferido para hacer lo que quiere es:

Integer i6 = Integer.valueOf(-128)
Krystian Cybulski
fuente
1
Echado a Integer es exactamente azúcar sintético para valueOf.
bestsss
44
Sí, pero a veces el azúcar sintético falla de manera sutil. He tenido algunas excepciones de puntero nulo difíciles de rastrear en aplicaciones grandes debido al auto-boxeo. Llegamos a tratar el auto-boxeo como errores para evitar dolores de cabeza en el futuro. La magia es buena, pero cuando falla, las cabezas duelen. Creo que es mejor ser explícito y ahorrarse los dolores de cabeza.
Krystian Cybulski
NPE son b1tch w / outboxing, cierto. Esp casos como for (int i in Collection<Integer>)b / c el NPE está en una ubicación absolutamente inesperada. En realidad, no uso Integer w / autoboxing ya que el rango de caché es pequeño (aunque se puede aumentar con la opción XX), pero tengo una clase llamada IntegerProvider (desde 1.1) para hacer lo mismo. Usando Map (any from java.util) Integer-> Cualquier cosa es generalmente un golpe de rendimiento a menos que se use para casos triviales y casi siempre hay una mejor solución.
bestsss
Transmitir int a Integer nunca puede causar ningún error, excepto el desbordamiento del montón, tal vez. Sin embargo, lo inverso no es cierto.
Ingo
@MattBall, no lo entiendo, el azúcar sintético se usa ampliamente: eggcorns.lascribe.net/forum/viewtopic.php?id=4400 y el sintético me suena mejor.
bestsss
9

Lo analiza Integer <minus operator> 128y no encuentra la variable Integer. Tendrá que envolver los -128corchetes:

Integer i3 = (Integer) (-128);  // compiles
Bohemio
fuente
He otorgado +1 a todas las demás respuestas porque todas son correctas también :)
Bohemian
7
Integer i3 = (Integer) (-128);

El problema es que el -compilador lo ve como un operador.

Brian Roach
fuente
6

La línea 3 se interpreta como si estuviera tratando de deducir 128 de la expresión entre paréntesis y la expresión entre paréntesis no es y expresión de tipo int (trata el operador '-' como un operador '-'). Si cambia la expresión a:

Integer i3 = (Integer) (-128);

entonces el compilador comprenderá que '-' es el signo menos unario que indica un número entero negativo.

Udi Cohen
fuente
3

El compilador de C # tiene el mismo comportamiento. Sin embargo, da una mejor pista de por qué no se compila:

Para emitir un valor negativo, debe encerrar el valor entre paréntesis

JefClaes
fuente