Qualche idea sul perché ho bisogno di lanciare un valore letterale intero a (int) qui?


122

Nell'esempio seguente

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

Non posso lanciare -128con (Integer)ma posso lanciare (int) -128.

Ho sempre pensato che -128fosse di inttipo e lanciarlo con (int)dovrebbe essere ridondante.

L'errore sulla riga con i3è

cannot find symbol variable Integer

L'ho provato con l'aggiornamento 29 di Java 6 e l'aggiornamento 1 di Java 7.

EDIT: ottieni lo stesso comportamento con +128invece di -128. Sembra esserci confusione tra operatori unari e binari.


5
qual è il tuo compilatore? Integer i = -128;questo dovrebbe essere compilato, però.
bestsss

strano, è Integer i3 = (Integer) (-128);conforme però.
Ing

2
@ Eng.Fouad, Peter, i simboli unari (+ -) hanno associatività da destra a sinistra e più, meno sono da sinistra a destra. L'effetto di -128 sarebbe lo stesso di +128 e mettere 0 davanti dovrebbe risolvere, cioè 0-128 o 0 + 128. (non posso testare bancomat ma scommetto che lo farà)
bestsss

Buona domanda! Personalmente mi piacerebbe vedere un riferimento JLS per la risoluzione di operatori unari / binari e quando un cast viene trattato come un'espressione. Altrimenti, potrebbe essere possibile che altri compilatori non lo considerino un errore!
Bringer128

1
Inoltre, per tua informazione, l'errore che ottengo nel mio IDE è Expression expecteddove si Integertrova.
Bringer128

Risposte:


151

Il compilatore tenta di sottrarre 128da (Integer)invece di -128eseguire il cast a Integer. Aggiungi ()per risolverlo

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

Secondo BoltClock nei commenti a cui il cast int funziona come previsto, perché è una parola riservata e quindi non può essere interpretata come un identificatore, il che ha senso per me.

E Bringer128 ha trovato il riferimento JLS 15.16 .

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

Come puoi vedere, il casting a un tipo primitivo richiede qualsiasi UnaryExpression, mentre il casting a un tipo di riferimento richiede un file UnaryExpressionNotPlusMinus. Questi sono definiti appena prima di CastExpression in JLS 15.15 .


31
Penso che sia perché intè una parola chiave in Java, ma Integernon lo è. Poiché intè una parola chiave, non puoi usarla come identificatore per una variabile o una classe, lasciando l'unica possibilità rimasta per essere un typecast. Questo lo spiegherebbe.
BoltClock

@BoltClock ha incorporato il tuo commento nella risposta.
Jens Schauder

3
Per rendere questa una risposta ancora più stellare, vuoi aggiungere il mio link al JLS?
Bringer128

3
Una ruga interessante (per me) su questo problema è come risolviamo il problema analogo in C #, che ha anche un'ambiguità nella grammatica tra "espressione tra parentesi come operando all'operatore di sottrazione binaria" e "operatore cast dove l'operando giusto del cast è un'espressione meno unaria ". Vedere la sezione 7.7.6 della specifica C # per una descrizione dettagliata dell'euristica che usiamo per cercare di essere intelligenti nel risolvere l'ambiguità.
Eric Lippert

1
@ BillK Perché dici questo? La specifica C # non si riferisce al sovraccarico degli operatori nella sezione 7.7.6, quindi non è stato un problema per loro.
Bringer128

48

Ho trovato il riferimento JLS. 15.16 .

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

Come puoi vedere, il casting a un tipo primitivo richiede qualsiasi UnaryExpression, mentre il casting a un tipo di riferimento richiede un file UnaryExpressionNotPlusMinus. Questi sono definiti appena prima di CastExpression in JLS 15.15 .

È necessario modificare il cast in un tipo primitivo:

... (int) -128;

Oppure puoi modificare l'espressione a destra del cast in un'espressione unaria non più-meno:

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

12

Il compilatore interpreta l' -operatore come meno di due argomenti, cioè sta cercando di sottrarre 128 da un altro numero chiamatoInteger , ma non esiste tale variabile nell'ambito.

Questo compila:

Integer i3 = (Integer) (-128)

Potresti aggiungere un commento sul perché (int)fa la differenza.
Peter Lawrey

1
È dovuto all'autoboxing, no?
Brian Roach,

9

Questo potrebbe avere a che fare con l'analisi della sintassi. Notare che

Integer i4 = (Integer) (-128); 

funziona bene.

In generale, non dovresti eseguire il cast alla classe Integer. Ciò implica qualcosa chiamato auto-boxing e può causare alcuni sottili errori nel codice. Il metodo preferito per fare ciò che vuoi è:

Integer i6 = Integer.valueOf(-128)

1
cast to Integer è esattamente zucchero sintetico per valueOf.
bestsss

4
sì, ma a volte lo zucchero sintetico fallisce in modi sottili. Ho avuto qualche difficoltà a rintracciare le eccezioni del puntatore nullo in applicazioni di grandi dimensioni a causa dell'auto-boxing. Siamo arrivati ​​al punto di trattare l'auto-boxing come errori per salvare il mal di testa in futuro. La magia è bella, ma quando fallisce, la testa fa male. Trovo sia meglio essere espliciti e risparmiarti il ​​mal di testa.
Krystian Cybulski

NPE è b1tch w / outboxing, vero. Casi specialmente come for (int i in Collection<Integer>)b / c l'NPE è in una posizione assolutamente inaspettata. In realtà non uso Integer con l'autoboxing poiché l'intervallo di cache è piccolo (anche se può essere aumentato con l'opzione XX) ma ho una classe chiamata IntegerProvider (dalla 1.1) per fare le stesse cose. Utilizzando Map (any da java.util) Integer-> Anything di solito è un problema di prestazioni a meno che non venga utilizzato per casi banali e quasi sempre c'è una soluzione migliore.
bestsss

Il cast di int su Integer non può mai causare errori, tranne forse l'overflow dell'heap. Il contrario, però, non è vero.
Ingo

@ MattBall, non lo capisco, lo zucchero sintetico è ampiamente usato: eggcorns.lascribe.net/forum/viewtopic.php?id=4400 e per me i suoni sintetici sono migliori.
bestsss

9

Lo sta analizzando come Integer <minus operator> 128e non trova la variabile Integer. Avrai bisogno di racchiudere -128tra parentesi:

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

Ho assegnato +1 a tutte le altre risposte perché anche loro sono corrette :)
Bohémien

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

Il problema è che il -compilatore lo vede come un operatore.


6

La riga 3 è interpretata come se si stesse tentando di dedurre 128 dall'espressione tra parentesi e l'espressione tra parentesi non è ed espressione di tipo int (tratta l'operatore "-" come un operatore "-"). Se modifichi l'espressione in:

Integer i3 = (Integer) (-128);

quindi il compilatore capirà che "-" è il meno unario che indica un numero intero negativo.


3

Il compilatore C # ha lo stesso comportamento. Fornisce un suggerimento migliore perché non riesce a compilare:

Per lanciare un valore negativo, è necessario racchiudere il valore tra parentesi

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.