Irgendeine Idee, warum ich hier ein ganzzahliges Literal in (int) umwandeln muss?

122

Im folgenden Beispiel

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

Ich kann nicht werfen -128mit , (Integer)aber ich warf kann (int) -128.

Ich dachte immer, -128es wäre von intTyp und das Casting mit (int)sollte überflüssig sein.

Der Fehler in der Zeile mit i3ist

cannot find symbol variable Integer

Ich habe dies mit Java 6 Update 29 und Java 7 Update 1 versucht.

EDIT: Sie erhalten das gleiche Verhalten mit +128statt -128. Es scheint eine Verwechslung zwischen unären und binären Operatoren zu sein.

Peter Lawrey
quelle
5
Was ist dein Compiler? Integer i = -128;Dies sollte jedoch kompiliert werden.
Bests
seltsam, Integer i3 = (Integer) (-128);entspricht aber.
Eng.Fouad
2
@ Eng.Fouad, Peter, unäre Symbole (+ -) haben Assoziativität von rechts nach links und Plus, Minus sind von links nach rechts. Der Effekt von -128 wäre der gleiche wie bei +128 und das Setzen von 0 vor sollte behoben werden, dh 0-128 oder 0 + 128. (Ich kann atm nicht testen, aber ich wette, es wird)
bestsss
Gute Frage! Ich persönlich würde gerne eine JLS-Referenz für die Auflösung von unären / binären Operatoren sehen und wenn eine Besetzung als Ausdruck behandelt wird. Andernfalls ist es möglich, dass andere Compiler dies nicht als Fehler betrachten!
Bringer128
1
Zu Ihrer Information, der Fehler, den ich in meiner IDE erhalte, ist, Expression expectedwo der Integerist.
Bringer128

Antworten:

151

Der Compiler versucht , subtrahieren 128von (Integer)anstelle von Gießen -128auf Integer. Fügen Sie hinzu (), um es zu beheben

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

Laut BoltClock in den Kommentaren intfunktioniert die Besetzung wie vorgesehen, da es sich um ein reserviertes Wort handelt und daher nicht als Kennung interpretiert werden kann, was für mich sinnvoll ist.

Und Bringer128 fand die JLS-Referenz 15.16 .

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

Wie Sie sehen können, erfordert das Umwandeln in einen primitiven Typ eine beliebige UnaryExpression, während das Umwandeln in einen Referenztyp a erfordert UnaryExpressionNotPlusMinus. Diese werden unmittelbar vor der CastExpression in JLS 15.15 definiert .

Jens Schauder
quelle
31
Ich denke, das liegt daran, dass es sich intum ein Schlüsselwort in Java handelt, aber Integernicht. Da intes sich um ein Schlüsselwort handelt, können Sie es nicht als Bezeichner für eine Variable oder eine Klasse verwenden, sodass nur noch eine Typumwandlung möglich ist. Das würde es erklären.
BoltClock
@BoltClock Hat Ihren Kommentar in die Antwort aufgenommen.
Jens Schauder
3
Möchten Sie meinen Link zum JLS hinzufügen, um diese Antwort noch besser zu machen?
Bringer128
3
Eine interessante (für mich) Falte in diesem Bereich ist, wie wir das analoge Problem in C # lösen, das auch in der Grammatik eine Mehrdeutigkeit zwischen "Klammerausdruck als Operand zum binären Subtraktionsoperator" und "Cast-Operator, bei dem der richtige Operand des Besetzung ist ein unärer Minus-Ausdruck ". In Abschnitt 7.7.6 der C # -Spezifikation finden Sie eine detaillierte Beschreibung der Heuristiken, mit denen wir versuchen, die Auflösung der Amgiguität klug zu gestalten.
Eric Lippert
1
@ BillK Warum sagst du das? Die C # -Spezifikation bezieht sich nicht auf das Überladen von Operatoren in Abschnitt 7.7.6, daher war dies für sie kein Problem.
Bringer128
48

Ich habe die JLS-Referenz gefunden. 15.16 .

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

Wie Sie sehen können, erfordert das Umwandeln in einen primitiven Typ eine beliebige UnaryExpression, während das Umwandeln in einen Referenztyp a erfordert UnaryExpressionNotPlusMinus. Diese werden unmittelbar vor der CastExpression in JLS 15.15 definiert .

Sie müssen entweder die Besetzung in einen primitiven Typ ändern:

... (int) -128;

Oder Sie können den Ausdruck rechts von der Besetzung in einen unären Plus-Minus-Ausdruck ändern:

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

Der Compiler interpretiert den -Operator mit zwei Argumenten minus, dh er versucht, 128 von einer anderen benannten Zahl zu subtrahieren Integer, aber es gibt keine solche Variable im Gültigkeitsbereich.

Dies kompiliert:

Integer i3 = (Integer) (-128)
Barend
quelle
Sie können einen Kommentar hinzufügen, warum dies (int)einen Unterschied macht.
Peter Lawrey
1
Es liegt an der Autobox, nein?
Brian Roach
9

Dies hat möglicherweise mit der Syntaxanalyse zu tun. Beachte das

Integer i4 = (Integer) (-128); 

funktioniert gut.

Im Allgemeinen sollten Sie nicht in die Integer-Klasse umwandeln. Dies beinhaltet etwas, das als Auto-Boxing bezeichnet wird, und kann einige subtile Fehler in Ihrem Code verursachen. Die bevorzugte Methode, um das zu tun, was Sie wollen, ist:

Integer i6 = Integer.valueOf(-128)
Krystian Cybulski
quelle
1
Cast to Integer ist genau synthetischer Zucker für valueOf.
Bests
4
Ja, aber manchmal versagt der synthetische Zucker auf subtile Weise. Ich hatte aufgrund des automatischen Boxens einige Schwierigkeiten, Nullzeigerausnahmen in großen Anwendungen aufzuspüren. Wir sind so weit gegangen, Auto-Boxing als Fehler zu behandeln, um in Zukunft Kopfschmerzen zu vermeiden. Magie ist schön, aber wenn sie versagt, schmerzen die Köpfe. Ich finde es besser, explizit zu sein und sich die Kopfschmerzen zu ersparen.
Krystian Cybulski
NPE sind b1tch w / outboxing, wahr. Vor allem in Fällen wie for (int i in Collection<Integer>)b / c befindet sich die NPE an einem absolut unerwarteten Ort. Ich verwende eigentlich keine Ganzzahl mit Autoboxing, da der Cache-Bereich klein ist (obwohl er mit der Option XX erweitert werden kann), habe aber eine Klasse namens IntegerProvider (seit 1.1), um genau das Gleiche zu tun. Verwenden von Map (beliebig aus java.util) Ganzzahl-> Alles ist normalerweise ein Leistungseinbruch, es sei denn, es wird für triviale Fälle verwendet und fast immer gibt es eine bessere Lösung.
Bests
Das Umwandeln von int in Integer kann niemals Fehler verursachen, außer möglicherweise einen Heap-Überlauf. Das Gegenteil ist jedoch nicht der Fall.
Ingo
@MattBall, ich verstehe es nicht ganz, synthetischer Zucker wird häufig verwendet: Eggcorns.lascribe.net/forum/viewtopic.php?id=4400 und synthetisch klingt für mich besser.
Bests
9

Es analysiert es als Integer <minus operator> 128und findet die Variable nicht Integer. Sie müssen die -128in Klammern setzen:

Integer i3 = (Integer) (-128);  // compiles
Böhmisch
quelle
Ich habe +1 für alle anderen Antworten vergeben, weil sie auch alle richtig sind :)
Bohemian
7
Integer i3 = (Integer) (-128);

Das Problem ist, dass der -Compiler es als Operator sieht.

Brian Roach
quelle
6

Zeile 3 wird so interpretiert, als würden Sie versuchen, 128 vom Ausdruck in der Klammer abzuleiten, und der Ausdruck in der Klammer ist nicht und Ausdruck vom Typ int (behandelt das '-' als '-' Operator). Wenn Sie den Ausdruck ändern in:

Integer i3 = (Integer) (-128);

dann wird der Compiler verstehen, dass '-' das unäre Minus ist, das eine negative ganze Zahl anzeigt.

Udi Cohen
quelle
3

Der C # -Compiler hat das gleiche Verhalten. Es gibt einen besseren Hinweis, warum es nicht kompiliert werden kann:

Um einen negativen Wert umzuwandeln, müssen Sie den Wert in Klammern setzen

JefClaes
quelle