Seit Java 5 haben wir das Ein- und Auspacken primitiver Typen, so dass int
es umbrochen wird java.lang.Integer
, und so weiter und so fort.
Ich sehe in letzter Zeit viele neue Java-Projekte (für die definitiv eine JRE von mindestens Version 5, wenn nicht sogar 6 erforderlich ist), die int
eher verwendet werden als java.lang.Integer
, obwohl es viel bequemer ist, letztere zu verwenden, da es einige Hilfsmethoden zum Konvertieren gibt zu long
Werten et al.
Warum verwenden einige noch primitive Typen in Java? Gibt es einen konkreten Vorteil?
java
primitive
primitive-types
autoboxing
jdk1.5
Naftuli Kay
quelle
quelle
new IntegeR(5) == new Integer(5)
nach den Regeln falsch bewertet werden sollte.Antworten:
In Joshua Blochs Effective Java , Punkt 5: "Vermeiden Sie unnötige Objekte", veröffentlicht er das folgende Codebeispiel:
und es dauert 43 Sekunden, um zu laufen. Wenn Sie das Long in das Primitiv aufnehmen, wird es auf 6,8 Sekunden reduziert ... Wenn dies ein Hinweis darauf ist, warum wir Primitive verwenden.
Der Mangel an nativer Wertgleichheit ist ebenfalls ein Problem (
.equals()
ist im Vergleich zu ziemlich ausführlich==
)für biziclop:
Ergebnisse in:
BEARBEITEN Warum kehrt (3) zurück
true
und (4) zurückfalse
?Weil sie zwei verschiedene Objekte sind. Die 256 Ganzzahlen, die Null am nächsten kommen [-128; 127] werden von der JVM zwischengespeichert, sodass sie für diese das gleiche Objekt zurückgeben. Außerhalb dieses Bereichs werden sie jedoch nicht zwischengespeichert, sodass ein neues Objekt erstellt wird. Um die Sache noch komplizierter zu machen, fordert das JLS, dass mindestens 256 Fliehgewichte zwischengespeichert werden. JVM-Implementierer können auf Wunsch weitere hinzufügen, was bedeutet, dass dies auf einem System ausgeführt werden kann, auf dem die nächsten 1024 zwischengespeichert werden und alle true zurückgeben ... #awkward
quelle
i
auch deklariertLong
!==
Operator Referenzidentitätsvergleiche fürInteger
Ausdrücke und Wertegleichheitsvergleiche fürint
Ausdrücke durchführt.Integer.equals()
existiert aus genau diesem Grund. Sie sollten nie verwenden==
in jedem nicht-primitiven Typ Wert zu vergleichen. Dies ist Java 101.Autounboxing kann zu schwer zu erkennenden NPEs führen
In den meisten Situationen ist die Nullzuweisung zu
in
viel weniger offensichtlich als oben.quelle
Boxed-Typen haben eine schlechtere Leistung und benötigen mehr Speicher.
quelle
Primitive Typen:
Bewerten Sie nun:
Es ist
true
. Kaum überraschend. Probieren Sie nun die Box-Typen aus:Bewerten Sie nun:
Es ist
false
. Wahrscheinlich. Hängt von der Laufzeit ab. Ist das Grund genug?quelle
Neben Leistungs- und Speicherproblemen möchte ich noch ein weiteres Problem ansprechen: Die
List
Schnittstelle wäre ohne defektint
.Das Problem ist die überladene
remove()
Methode (remove(int)
vs.remove(Object)
).remove(Integer)
würde immer beschließen, letzteres aufzurufen, so dass Sie ein Element nicht durch Index entfernen konnten.Auf der anderen Seite gibt es eine Gefahr beim Hinzufügen und Entfernen von
int
:quelle
Vector
hatteremoveElementAt(int)
von Anfang an.remove(int)
wurde mit dem Sammlungsframework in Java 1.2 eingeführt.List
API entwickelt wurde, gab es weder Generics noch Autoboxing, so dass es keine Chance gab, sich zu verwechselnremove(int)
undremove(Object)
…Kannst du dir wirklich eine vorstellen?
Schleife mit java.lang.Integer statt? Eine java.lang.Integer ist unveränderlich, sodass bei jedem Inkrementieren der Schleife ein neues Java-Objekt auf dem Heap erstellt wird, anstatt nur das int auf dem Stapel mit einem einzelnen JVM-Befehl zu inkrementieren. Die Leistung wäre teuflisch.
Ich würde wirklich nicht zustimmen, dass es viel bequemer ist, java.lang.Integer als int zu verwenden. Andererseits. Autoboxing bedeutet, dass Sie int dort verwenden können, wo Sie sonst gezwungen wären, Integer zu verwenden, und der Java-Compiler kümmert sich um das Einfügen des Codes, um das neue Integer-Objekt für Sie zu erstellen. Beim Autoboxing geht es darum, Ihnen die Verwendung eines Int zu ermöglichen, bei dem eine Ganzzahl erwartet wird, wobei der Compiler die entsprechende Objektkonstruktion einfügt. Es beseitigt oder reduziert in keiner Weise die Notwendigkeit des int in erster Linie. Mit Autoboxing bekommen Sie das Beste aus beiden Welten. Sie erhalten automatisch eine Ganzzahl, die für Sie erstellt wird, wenn Sie ein Heap-basiertes Java-Objekt benötigen, und Sie erhalten die Geschwindigkeit und Effizienz eines Int, wenn Sie nur arithmetische und lokale Berechnungen durchführen.
quelle
Primitive Typen sind viel schneller:
Ganzzahl (alle Zahlen und auch eine Zeichenfolge) ist ein unveränderlicher Typ: Einmal erstellt, kann er nicht mehr geändert werden. Wenn
i
Integeri++
wäre, würde ein neues Integer-Objekt erstellt - viel teurer in Bezug auf Speicher und Prozessor.quelle
i++
für eine andere Variable tun. Daher muss Integer unveränderlich sein, um dies zu tun (oder zumindesti++
müsste dies ohnehin ein neues Integer-Objekt erstellen). (Und die primitiven Werte sind auch unveränderlich - Sie bemerken dies nur nicht, da sie keine Objekte sind.)++
ist hier ein roter Hering. Stellen Sie sich vor, Java wurde erweitert, um das Überladen von Operatoren auf wirklich einfache Weise zu unterstützen, sodass Sie, wenn eine Klasse (z. B.Integer
eine Methode)plus
,i + 1
stattdessen schreiben könneni.plus(1)
. Nehmen Sie auch an, dass der Compiler intelligent genug ist, umi++
in ihn zu expandiereni = i + 1
. Jetzt können Sie sageni++
und effektiv "die Variable i inkrementieren", ohneInteger
veränderlich zu sein.In erster Linie Gewohnheit. Wenn Sie acht Jahre lang in Java codiert haben, akkumulieren Sie eine beträchtliche Menge an Trägheit. Warum ändern, wenn es keinen zwingenden Grund dafür gibt? Es ist nicht so, als ob die Verwendung von Grundelementen in Schachteln zusätzliche Vorteile mit sich bringt.
Der andere Grund ist zu behaupten, dass dies
null
keine gültige Option ist. Es wäre sinnlos und irreführend, die Summe zweier Zahlen oder einer Schleifenvariablen als zu deklarierenInteger
.Es gibt auch den Leistungsaspekt, obwohl der Leistungsunterschied in vielen Fällen nicht kritisch ist (obwohl er ziemlich schlecht ist), schreibt niemand gerne Code, der genauso einfach und schneller geschrieben werden kann, als wir es bereits sind gewöhnt an.
quelle
Übrigens hat Smalltalk nur Objekte (keine Grundelemente), und dennoch hatten sie ihre kleinen Ganzzahlen (mit nicht allen 32 Bits, nur 27 oder so) optimiert, um keinen Heap-Speicherplatz zuzuweisen, sondern einfach ein spezielles Bitmuster zu verwenden. Auch andere gängige Objekte (true, false, null) hatten hier spezielle Bitmuster.
Zumindest auf 64-Bit-JVMs (mit einem 64-Bit-Zeigernamensraum) sollte es also möglich sein, überhaupt keine Objekte mit Integer, Character, Byte, Short, Boolean, Float (und Small Long) zu haben (abgesehen von diesen erstellt) durch explizite
new ...()
) nur spezielle Bitmuster, die von den normalen Operatoren recht effizient manipuliert werden könnten.quelle
Ich kann nicht glauben, dass niemand erwähnt hat, was meiner Meinung nach der wichtigste Grund ist: "int" ist so viel einfacher zu tippen als "Integer". Ich denke, die Leute unterschätzen die Wichtigkeit einer prägnanten Syntax. Die Leistung ist nicht wirklich ein Grund, sie zu vermeiden, da die meiste Zeit, wenn man Zahlen verwendet, in Schleifenindizes liegt und das Inkrementieren und Vergleichen dieser Kosten in keiner nicht trivialen Schleife (unabhängig davon, ob Sie int oder Integer verwenden) nichts kostet.
Der andere gegebene Grund war, dass Sie NPEs erhalten können, aber das ist mit Boxed-Typen extrem einfach zu vermeiden (und es wird garantiert vermieden, solange Sie sie immer mit Nicht-Null-Werten initialisieren).
Der andere Grund war, dass (new Long (1000)) == (new Long (1000)) falsch ist, aber das ist nur eine andere Art zu sagen, dass ".equals" keine syntaktische Unterstützung für Boxed-Typen hat (im Gegensatz zu den Operatoren <,>) , =, etc), also kommen wir zurück zum Grund der "einfacheren Syntax".
Ich denke, Steve Yegges nicht-primitives Loop-Beispiel veranschaulicht meinen Standpunkt sehr gut: http://sites.google.com/site/steveyegge2/language-trickery-and-ejb
Denken Sie darüber nach: Wie oft verwenden Sie Funktionstypen in Sprachen, die eine gute Syntax für sie haben (wie jede funktionale Sprache, Python, Ruby und sogar C), im Vergleich zu Java, wo Sie sie mithilfe von Schnittstellen wie Runnable und Callable und simulieren müssen namenlose Klassen.
quelle
Einige Gründe, Primitive nicht loszuwerden:
Wenn es beseitigt wird, würden keine alten Programme ausgeführt.
Die gesamte JVM müsste neu geschrieben werden, um diese neue Sache zu unterstützen.
Sie müssten den Wert und die Referenz speichern, wodurch mehr Speicher benötigt wird. Wenn Sie ein großes Array von Bytes haben, ist die Verwendung von
byte
's erheblich kleiner als die Verwendung vonByte
' s.Zu deklarieren,
int i
dann Sachen zu machen,i
würde zu keinen Problemen führen, aber zu deklarierenInteger i
und dann dasselbe zu tun, würde zu einer NPE führen.Betrachten Sie diesen Code:
Wäre falsch. Die Bediener müssten überlastet werden, und das würde zu einer umfassenden Umschreibung führen.
Objekt-Wrapper sind erheblich langsamer als ihre primitiven Gegenstücke.
quelle
Objekte sind viel schwerer als primitive Typen, daher sind primitive Typen viel effizienter als Instanzen von Wrapper-Klassen.
Primitive Typen sind sehr einfach: Zum Beispiel ist ein int 32 Bit groß und nimmt genau 32 Bit im Speicher ein und kann direkt bearbeitet werden. Ein Integer-Objekt ist ein vollständiges Objekt, das (wie jedes Objekt) auf dem Heap gespeichert werden muss und auf das nur über einen Verweis (Zeiger) zugegriffen werden kann. Es nimmt höchstwahrscheinlich auch mehr als 32 Bit (4 Bytes) Speicher in Anspruch.
Die Tatsache, dass Java zwischen primitiven und nicht-primitiven Typen unterscheidet, ist jedoch auch ein Zeichen des Alters der Java-Programmiersprache. Neuere Programmiersprachen haben diese Unterscheidung nicht; Der Compiler einer solchen Sprache ist intelligent genug, um selbst herauszufinden, ob Sie einfache Werte oder komplexere Objekte verwenden.
Zum Beispiel gibt es in Scala keine primitiven Typen; Es gibt eine Klasse Int für ganze Zahlen, und ein Int ist ein reales Objekt (auf das Sie Methoden anwenden können usw.). Wenn der Compiler Ihren Code kompiliert, verwendet er hinter den Kulissen primitive Ints. Die Verwendung eines Int ist also genauso effizient wie die Verwendung eines primitiven Int in Java.
quelle
Zusätzlich zu dem, was andere gesagt haben, werden primitive lokale Variablen nicht vom Heap zugewiesen, sondern auf dem Stapel. Objekte werden jedoch vom Heap zugeordnet und müssen daher mit Müll gesammelt werden.
quelle
Primitive Typen haben viele Vorteile:
quelle
Es ist schwer zu wissen, welche Optimierungen unter der Decke stattfinden.
Für den lokalen Gebrauch erwarte ich, dass die Leistung gleich oder ähnlich ist , wenn der Compiler über genügend Informationen verfügt, um Optimierungen ohne die Möglichkeit des Nullwerts vorzunehmen .
Anordnungen von Grundelementen unterscheiden sich jedoch offensichtlich stark von Sammlungen von Grundelementen in Schachteln. Dies ist sinnvoll, da nur sehr wenige Optimierungen tief in einer Sammlung möglich sind.
Darüber hinaus
Integer
hat es einen viel höheren logischen Overhead im Vergleich zuint
: Jetzt müssen Sie sich Gedanken darüber machen, obint a = b + c;
eine Ausnahme ausgelöst wird oder nicht .Ich würde die Grundelemente so oft wie möglich verwenden und mich auf die Factory-Methoden und Autoboxing verlassen, um mir die semantisch leistungsfähigeren Box-Typen zu geben, wenn sie benötigt werden.
quelle
Nebenbei bemerkt, es würde mir nichts ausmachen, wenn so etwas seinen Weg nach Java findet.
Wobei die for-Schleife loop1 automatisch von 0 auf 1000 oder 1000 erhöht
Wobei die for-Schleife loop1 1000 automatisch auf 0 dekrementiert.
quelle
Sie sollten sich fragen, warum ein Klassen- / Objekttyp erforderlich ist
Der Grund für den Objekttyp ist, unser Leben im Umgang mit Sammlungen zu erleichtern. Grundelemente können nicht direkt zu List / Map hinzugefügt werden, sondern Sie müssen eine Wrapper-Klasse schreiben. Readymade Integer-Klassen helfen Ihnen hier und es gibt viele Dienstprogrammmethoden wie Integer.pareseInt (str)
quelle
Ich stimme früheren Antworten zu, die Verwendung von primitiven Wrapper-Objekten kann teuer sein. Wenn die Leistung in Ihrer Anwendung jedoch nicht kritisch ist, vermeiden Sie Überläufe bei der Verwendung von Objekten. Beispielsweise:
Der Wert von
bigNumber
ist -2147483647, und Sie würden erwarten, dass er 2147483649 beträgt. Dies ist ein Fehler im Code, der behoben werden würde, indem Folgendes ausgeführt wird:Und
bigNumber
wäre 2147483649. Diese Art von Fehlern ist manchmal leicht zu übersehen und kann zu unbekanntem Verhalten oder Schwachstellen führen (siehe CWE-190 ).Wenn Sie Wrapper-Objekte verwenden, wird der entsprechende Code nicht kompiliert.
Daher ist es einfacher, diese Art von Problemen zu stoppen, indem Sie primitive Wrapper-Objekte verwenden.
Ihre Frage ist bereits so beantwortet, dass ich nur antworte, um ein bisschen mehr Informationen hinzuzufügen, die zuvor nicht erwähnt wurden.
quelle
Weil JAVA alle mathematischen Operationen in primitiven Typen ausführt. Betrachten Sie dieses Beispiel:
Hier können Erinnerungs- und unäre Plus-Operationen nicht auf den Integer-Typ (Referenz) angewendet werden. Der Compiler führt das Unboxing durch und führt die Operationen aus.
Stellen Sie also sicher, wie viele Autoboxing- und Unboxing-Vorgänge im Java-Programm ausgeführt werden. Seitdem dauert es einige Zeit, um diese Vorgänge auszuführen.
Im Allgemeinen ist es besser, Argumente vom Typ Referenz und Ergebnis vom primitiven Typ beizubehalten.
quelle
Die primitiven Typen sind viel schneller und benötigen viel weniger Speicher . Daher möchten wir sie vielleicht lieber verwenden.
Andererseits erlaubt die aktuelle Java-Sprachspezifikation nicht die Verwendung primitiver Typen in den parametrisierten Typen (Generika), in den Java-Sammlungen oder in der Reflection-API.
Wenn unsere Anwendung Sammlungen mit einer großen Anzahl von Elementen benötigt, sollten wir in Betracht ziehen, Arrays mit einem möglichst „wirtschaftlichen“ Typ zu verwenden.
* Detaillierte Informationen finden Sie in der Quelle: https://www.baeldung.com/java-primitives-vs-objects
quelle
Um es kurz zu machen: Primitive Typen sind schneller und benötigen weniger Speicher als Boxed-Typen
quelle