Ich habe diesen Beitrag negativ und positiv Null gelesen .
Nach meinem Verständnis sollte folgender Code geben true
und true
als Ausgabe.
Es gibt jedoch false
und true
als Ausgabe.
Ich vergleiche negative Null mit einer positiven Null.
public class Test {
public static void main(String[] args) {
float f = 0;
float f2 = -f;
Float F = new Float(f);
Float F1 = new Float(f2);
System.out.println(F1.equals(F));
int i = 0;
int i2 = -i;
Integer I = new Integer(i);
Integer I1 = new Integer(i2);
System.out.println(I1.equals(I));
}
}
Warum haben wir ein unterschiedliches Verhalten für Nullen für Integer
und Float
?
i
undi2
sind genau das gleiche. Wenn Sie dann neueInteger
s erstellen , schließen beide genau den gleichen Wert ein.I1.equals(I)
wird wahr sein.int i = Integer.MIN_VALUE, i2 = -i;
...new
für die Wrapper-Typen zu verwenden. Verwenden Sie einfach zBInteger i = 0, i2 = -i; System.out.println(i.equals(i2)); Float f1 = 0f, f2 = -f1; System.out.println(f1.equals(f2));
Antworten:
Ints und Floats sind in Java ziemlich unterschiedliche Bestien. Ints werden als Zweierkomplement codiert , das einen einzelnen 0-Wert hat. Floats verwenden IEEE 754 (die 32-Bit-Variante für Floats und 64-Bit für Doubles). IEEE 754 ist etwas komplex, aber für diese Antwort müssen Sie nur wissen, dass es drei Abschnitte hat, von denen der erste ein Vorzeichenbit ist. Das heißt, für jeden Float gibt es eine positive und eine negative Variante¹. Das schließt 0 ein, also haben Floats tatsächlich zwei "Null" -Werte, +0 und -0.
Abgesehen davon ist das von Ints verwendete Komplement der beiden nicht die einzige Möglichkeit, Ganzzahlen in der Informatik zu codieren. Es gibt andere Methoden, wie das Komplement von Einsen , aber sie haben Macken - wie sowohl +0 als auch -0 als unterschiedliche Werte. ;-);
Wenn Sie Float-Primitive (und Doubles) vergleichen, behandelt Java +0 und -0 als gleich. Wenn Sie sie jedoch einpacken, werden sie von Java separat behandelt, wie in beschrieben
Float#equals
. Auf diese Weise kann die Methode equals mit ihrerhashCode
Implementierung (sowiecompareTo
) konsistent sein , bei der nur die Bits des Gleitkommas (einschließlich des vorzeichenbehafteten Werts) verwendet und unverändert in ein int verschoben werden.Sie hätten eine andere Option für equals / hashCode / compareTo auswählen können, aber sie haben es nicht getan. Ich bin mir nicht sicher, welche Designüberlegungen es gab. Aber in mindestens einer Hinsicht würde
Float#equals
immer von den Float-Primitiven abweichen==
: In PrimitivenNaN != NaN
, aber für alle Objekte,o.equals(o)
muss auch wahr sein . Das heißt, wenn Sie hattenFloat f = Float.NaN
, dannf.equals(f)
obwohlf.floatValue() != f.floatValue()
.¹ NaN-Werte (keine Zahl) haben ein Vorzeichenbit, aber keine andere Bedeutung als für die Bestellung, und Java ignoriert sie (auch für die Bestellung).
quelle
Dies ist eine Ausnahme von Float gleich
Das Warum wird auch beschrieben:
-0 und 0 werden mit Floats Bit 31 unterschiedlich dargestellt:
Dies ist in nicht der Fall
Integer
quelle
Für die ganzen Zahlen gibt es keine Unterscheidung zwischen -0 und 0 für ganze Zahlen, da die Zweierkomplementdarstellung verwendet wird . Also dein ganzzahliges Beispiel
i
undi1
genau das gleiche.Für die Floats gibt es eine -0-Darstellung, und ihr Wert entspricht 0, aber die Bitdarstellung ist unterschiedlich. Daher hätten neuer Float (0f) und neuer Float (-0f) unterschiedliche Darstellungen.
Sie können den Unterschied in den Bitdarstellungen sehen.
Und wenn Sie das weglassen, um das
f
zu deklarieren-0f
, wird es als Ganzzahl behandelt, und Sie werden keinen Unterschied in der Ausgabe sehen.quelle
0.0f == -0.0f
. Das unterschiedliche Verhalten ist also nur injava.lang.Float
.float
, der in dieser Hinsicht IEEE754 entspricht, und demjava.lang.Float
, der dies nicht tut. Nur der Unterschied in der Bitdarstellung reicht also nicht aus, um dies zu erklären.