Die Grenze von int
liegt zwischen -2147483648 und 2147483647.
Wenn ich eingebe
int i = 2147483648;
dann fordert Eclipse unter "2147483648" eine rote Unterstreichung auf.
Aber wenn ich das mache:
int i = 1024 * 1024 * 1024 * 1024;
es wird gut kompiliert.
public class Test {
public static void main(String[] args) {
int i = 2147483648; // error
int j = 1024 * 1024 * 1024 * 1024; // no error
}
}
Vielleicht ist es eine grundlegende Frage in Java, aber ich habe keine Ahnung, warum die zweite Variante keinen Fehler erzeugt.
2147483648
: Dieses Wort macht keinen Sinn.Antworten:
An dieser Aussage ist nichts auszusetzen. Sie multiplizieren nur 4 Zahlen und weisen sie einem Int zu. Es kommt zufällig zu einem Überlauf. Dies unterscheidet sich von der Zuweisung eines einzelnen Literals , das beim Kompilieren auf Grenzen überprüft wird.
Es ist das Out-of-Bound- Literal , das den Fehler verursacht, nicht die Zuweisung :
Im Gegensatz dazu würde ein
long
Literal gut kompilieren:Beachten Sie, dass in der Tat, das Ergebnis ist immer noch zur Compile-Zeit berechnet , weil
1024 * 1024 * 1024 * 1024
a konstanten Ausdruck :wird:
Beachten Sie, dass das Ergebnis (
0
) einfach geladen und gespeichert wird und keine Multiplikation stattfindet.Von JLS §3.10.1 (danke an @ChrisK für das Aufrufen in den Kommentaren):
quelle
-1 + 1
ist es harmlos. Aber1024^4
es könnte Menschen mit völlig unerwarteten Ergebnissen blind machen, weit entfernt von dem, was sie erwarten würden. Ich denke, es sollte mindestens eine Warnung oder ein Hinweis für den Benutzer geben und diese nicht stillschweigend ignorieren.1024 * 1024 * 1024 * 1024
und2147483648
haben nicht den gleichen Wert in Java.Tatsächlich ist es in Java
2147483648
nicht einmal ein Wert (obwohl dies der Fall2147483648L
ist). Der Compiler weiß buchstäblich nicht, was es ist oder wie man es benutzt. Also jammert es.1024
ist ein gültiges int in Java und ein gültigesint
multipliziert mit einem anderen gültigenint
ist immer ein gültigesint
. Auch wenn es nicht derselbe Wert ist, den Sie intuitiv erwarten würden, da die Berechnung überläuft.Beispiel
Betrachten Sie das folgende Codebeispiel:
Würden Sie erwarten, dass dies einen Kompilierungsfehler erzeugt? Es wird jetzt etwas rutschiger.
Was ist, wenn wir eine Schleife mit 3 Iterationen setzen und in der Schleife multiplizieren?
Der Compiler kann zwar optimieren, das Verhalten des Programms jedoch nicht ändern.
Einige Informationen darüber, wie dieser Fall tatsächlich behandelt wird:
In Java und vielen anderen Sprachen bestehen Ganzzahlen aus einer festen Anzahl von Bits. Berechnungen, die nicht in die angegebene Anzahl von Bits passen, laufen über . Die Berechnung wird grundsätzlich in Java Modul 2 ^ 32 durchgeführt, wonach der Wert wieder in eine vorzeichenbehaftete Ganzzahl umgewandelt wird.
Andere Sprachen oder APIs verwenden eine dynamische Anzahl von Bits (
BigInteger
in Java), lösen eine Ausnahme aus oder setzen den Wert auf einen magischen Wert, z. B. keine Zahl.quelle
2147483648
IST NOCH KEIN WERT (obwohl dies der Fall2147483648L
ist)" den Punkt, den @arshajii anstrebte , wirklich zementiert.1024 * 1024 * 1024 * 1024
damit umgegangen wird, wollte ich wirklich betonen, dass es nicht dasselbe ist wie Schreiben2147473648
. Es gibt viele Möglichkeiten (und Sie haben einige aufgelistet), wie eine Sprache möglicherweise damit umgehen kann. Es ist einigermaßen getrennt und nützlich. Also werde ich es verlassen. Viele Informationen werden zunehmend notwendig, wenn Sie eine hochrangige Antwort auf eine beliebte Frage haben.Das von Ihnen vorgeschlagene Verhalten, dh die Erstellung einer Diagnosemeldung, wenn eine Berechnung einen Wert erzeugt, der größer als der größte Wert ist, der in einer Ganzzahl gespeichert werden kann, ist eine Funktion . Damit Sie eine Funktion verwenden können, muss die Funktion als gute Idee angesehen, entworfen, spezifiziert, implementiert, getestet, dokumentiert und an Benutzer versendet werden.
Für Java sind eines oder mehrere der Dinge auf dieser Liste nicht aufgetreten, und daher verfügen Sie nicht über die Funktion. Ich weiß nicht welches; Sie müssten einen Java-Designer fragen.
Für C # sind all diese Dinge passiert - vor ungefähr vierzehn Jahren - und so hat das entsprechende Programm in C # seit C # 1.0 einen Fehler erzeugt.
quelle
Neben der Antwort von arshajii möchte ich noch eines zeigen:
Es ist nicht die Zuweisung , die den Fehler verursacht, sondern einfach die Verwendung des Literal . Wenn du es versuchst
Sie werden feststellen, dass es auch einen Kompilierungsfehler verursacht, da die rechte Seite immer noch eine ist
int
-literal ist und außerhalb des Bereichs liegt.Operationen mit
int
-Werten (und dazu gehören auch Zuweisungen) können ohne Kompilierungsfehler (und auch ohne Laufzeitfehler) überlaufen, aber der Compiler kann diese zu großen Literale einfach nicht verarbeiten.quelle
A: Weil es kein Fehler ist.
Hintergrund: Die Multiplikation
1024 * 1024 * 1024 * 1024
führt zu einem Überlauf. Ein Überlauf ist sehr oft ein Fehler. Unterschiedliche Programmiersprachen führen bei Überläufen zu unterschiedlichem Verhalten. Zum Beispiel nennen C und C ++ es "undefiniertes Verhalten" für vorzeichenbehaftete Ganzzahlen, und das Verhalten ist als vorzeichenlose Ganzzahlen definiert (nehmen Sie das mathematische Ergebnis, addieren SieUINT_MAX + 1
, solange das Ergebnis negativ ist, subtrahieren SieUINT_MAX + 1
, solange das Ergebnis größer als istUINT_MAX
).Im Fall von Java, wenn das Ergebnis einer Operation mit
int
Werten nicht im zulässigen Bereich liegt, addiert oder subtrahiert Java konzeptionell 2 ^ 32, bis das Ergebnis im zulässigen Bereich liegt. Die Aussage ist also völlig legal und nicht fehlerhaft. Es führt einfach nicht zu dem erhofften Ergebnis.Sie können sicherlich darüber streiten, ob dieses Verhalten hilfreich ist und ob der Compiler Sie warnen sollte. Ich würde persönlich sagen, dass eine Warnung sehr nützlich wäre, aber ein Fehler wäre falsch, da es sich um legales Java handelt.
quelle