Frage

Autoboxing ist ziemlich beängstigend. Während ich den Unterschied zwischen == und .equals vollständig verstehen, habe ich kann nicht umhin, die Hölle der Follow Bug aus mir:

    final List<Integer> foo = Arrays.asList(1, 1000);
    final List<Integer> bar = Arrays.asList(1, 1000);
    System.out.println(foo.get(0) == bar.get(0));
    System.out.println(foo.get(1) == bar.get(1));

Das Druck

true
false

Warum haben sie es tun, auf diese Weise? Es ist etwas mit gecached Ganzen Zahlen zu tun, aber wenn das der Fall ist, warum nicht sie nur alle ganzen Zahlen von dem Programm verwendet cachen? Oder warum nicht die JVM immer automatisch unbox zu primitiv?

Drucken false false oder true true wäre gewesen Art und Weise besser.

Bearbeiten

Ich bin nicht einverstanden zu Bruch des alten Code. Indem brach foo.get(0) == bar.get(0) return true Sie den Code bereits.

Kann man das nicht durch Ersetzen Integer mit int in Byte-Code (solange es nie null zugeordnet ist) an der Compiler Ebene gelöst werden

War es hilfreich?

Lösung

  • Warum haben sie es tun, auf diese Weise?

Jeder Integer zwischen -128 und 127 durch java zwischengespeichert. Sie taten dies, angeblich für den Leistungsvorteil. Auch wenn sie auf diese Entscheidung nun zurück gehen wollte, dann ist es unwahrscheinlich, dass sie tun würde. Wenn jemand gebaut Code auf je würde bricht ihr Code, wenn es wurde herausgenommen. Für Hobby-Codierung, dies vielleicht spielt keine Rolle, sondern auch für Unternehmen Code, die Menschen bekommen verärgert und Klagen geschehen.

  • Warum sie nicht nur alle ganzen Zahlen von dem Programm verwendet cachen?

Alle ganzen Zahlen kann nicht zwischengespeichert werden, weil die Speicher Auswirkungen wären enorm.

  • Warum funktioniert die JVM immer automatisch unbox zu primitiv?

Da die JVM kann nicht wissen, was Sie wollten. Auch könnte diese Änderung leicht Legacy-Code bricht nicht gebaut, diesen Fall zu behandeln.

Wenn die JVM automatisch unboxed zu Primitiven auf Anrufe ==, wird dieses Problem tatsächlich mehr geworden verwirrend. Jetzt müssen Sie daran denken, dass == immer Objektreferenzen vergleicht, es sei denn, die Objekte unboxed sein kann. Dies würde dazu führen, noch mehr seltsame Fälle genau wie die verwirrend Sie oben angegeben.

Rather sorgt dann zu hart darüber, gerade diese Regel erinnert statt:

NIE vergleichen Objekte mit ==, wenn Sie beabsichtigen, sie durch ihre Referenzen verglichen werden. Wenn Sie das tun, kann ich nicht denken Sie an ein Szenario, in dem Sie auf ein Problem stoßen würde.

Andere Tipps

Können Sie sich vorstellen, wie schlecht die Leistung wäre, wenn jeder Integer Aufwand für die Internierung durch? Auch funktioniert nicht für new Integer.

Die Java-Sprache (keine JVM Ausgabe) kann nicht immer automatisch unbox weil Code ausgelegt für Pre-1.5 Java soll noch arbeiten.

Integers im Byte-Bereich ist das gleiche Objekt, weil sie zwischengespeichert wird. Integers außerhalb des Byte-Bereich sind es nicht. Wenn alle Zahlen werden im Cache gespeichert wurden, stellen die Speicher erforderlich.

Und von hier

  

Das Ergebnis all dieser Magie ist, dass man weitgehend den Unterschied zwischen int und Integer, mit ein paar Einschränkungen ignorieren können. Ein Integer-Ausdruck kann einen Nullwert hat. Wenn Ihr Programm zu autounbox null versucht, wird es eine Nullpointer werfen. Die Operator == führt Referenzidentitätsvergleiche auf Integer-Ausdrücke und Wertgleichheit Vergleiche auf int Ausdrücken. Schließlich gibt es Performance-Kosten im Zusammenhang mit Boxen und Unboxing, auch wenn es geschieht automatisch

Wenn Sie komplett überspringen Autoboxing, Sie immer noch dieses Verhalten bekommen.

final List<Integer> foo =
  Arrays.asList(Integer.valueOf( 1 ), Integer.valueOf( 1000 ));
final List<Integer> bar =
  Arrays.asList(Integer.valueOf( 1 ), Integer.valueOf( 1000 ));

System.out.println(foo.get(0) == bar.get(0)); // true
System.out.println(foo.get(1) == bar.get(1)); // false

Seien deutlicher, wenn Sie ein bestimmtes Verhalten wollen:

final List<Integer> foo =
  Arrays.asList( new Integer( 1 ), new Integer( 1000 ));
final List<Integer> bar =
  Arrays.asList( new Integer( 1 ), new Integer( 1000 ));

System.out.println(foo.get(0) == bar.get(0)); // false
System.out.println(foo.get(1) == bar.get(1)); // false

Dies ist ein Grund, warum Eclipse-hat als Warnung von Standard-Autoboxing.

Viele Menschen haben Probleme mit diesem Thema, auch Menschen, die schreiben Bücher über Java.

In Pro Java Programming , bloßer Zoll unterschreitet spricht der Autor über Probleme bei der Verwendung auto-boxed ganze Zahlen als Schlüssel in einem IdentityHashMap verwendet er auto-boxed Integer Schlüssel in einem WeakHashMap. Die Beispielwerte er Verwendungen sind größer als 128, so seine Garbage Collection Aufruf erfolgreich ist. Wenn jemand sein Beispiel und Gebrauchswerte verwenden, die kleiner als 128 aber wäre sein Beispiel nicht (wegen des Schlüssel perma-Cache gespeichert ist).

Wenn Sie schreiben

foo.get(0)

die Compiler keine Rolle spielt, wie Sie die Liste erstellt. Es sieht nur in dem Kompilierung-Typ der Liste foo. Also, wenn das ein List ist es behandeln, dass als List , wie es tun soll, und eine List 's get () immer einen Integer zurückgibt. Wenn Sie die == verwenden, dann haben Sie zu schreiben

System.out.println(foo.get(0).intValue() == bar.get(0).intValue());

nicht

System.out.println(foo.get(0) == bar.get(0));

, denn das hat eine ganz andere Bedeutung.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top