Wann werden Wrapper-Klasse und primitiver Typ verwendet?

Antworten:

69

Andere haben erwähnt, dass bestimmte Konstrukte wie CollectionsObjekte erfordern und dass Objekte mehr Overhead haben als ihre primitiven Gegenstücke (Speicher & Boxen).

Eine weitere Überlegung ist:

Es kann nützlich sein, Objekte zu initialisieren nulloder nullParameter an eine Methode / einen Konstruktor zu senden , um den Status oder die Funktion anzuzeigen. Dies ist mit Grundelementen nicht möglich.

Viele Programmierer initialisieren Zahlen mit 0 (Standard) oder -1, um dies anzuzeigen. Je nach Szenario kann dies jedoch falsch oder irreführend sein.

Dies wird auch die Szene für einen NullPointerExceptionFall festlegen, in dem etwas falsch verwendet wird, was viel programmiererfreundlicher ist als ein beliebiger Fehler auf der ganzen Linie.

pstanton
quelle
15
"Es kann praktisch sein, Objekte auf null zu initialisieren". Es kann nicht praktisch sein, da dies falsch ist. Wenn das Feld optional ist, sollten Sie dies explizit angeben.
Eddie Jamsession
8
lol @EddieJamsession danke, ich werde nie wieder auf null initialisieren. (pfffft)
pstanton
@EddieJamsession Wenn das Initialisieren von Objekten auf Null, um einen Fehler beim Festlegen des tatsächlichen Werts anzuzeigen, fehlgeschlagen ist, wie würden Sie sonst vorschlagen, dieses Problem zu beheben? Oh, ich habe gerade festgestellt, als ich das tippe: Ausnahmen. Eine NullPointerException ist zu allgemein. Es ist besser, sehr spezielle benutzerdefinierte Ausnahmen zu verwenden, um anzuzeigen, was schief gelaufen ist. Gut, ich mache das von jetzt an ...
klaar
1
@EddieJamsession Nachdem ich die Angelegenheit gelesen habe, bin ich auf das Konzept eines optionalen Objekts gestoßen. Richtig.
Klaar
18

Im Allgemeinen sollten Sie primitive Typen verwenden, es sei denn, Sie benötigen aus irgendeinem Grund ein Objekt (z. B. zum Einfügen in eine Sammlung). Betrachten Sie auch dann einen anderen Ansatz, für den kein Objekt erforderlich ist, wenn Sie die numerische Leistung maximieren möchten. Dies wird in der Dokumentation empfohlen , und dieser Artikel zeigt, wie Auto-Boxing einen großen Leistungsunterschied verursachen kann.

Matthew Flaschen
quelle
3
Der Leistungseinbruch ist nicht so groß, dass die Lesbarkeit / Zuverlässigkeit des Codes in den Hintergrund treten sollte.
Pstanton
2
Erstens macht eine angemessene Verwendung von Grundelementen Ihren Code nicht unleserlich. Zweitens ist der Leistungseinbruch in einigen Fällen erheblich. Es ist absurd zu sagen, dass es niemals so ist.
Matthew Flaschen
1
@pstanton: bitte erkläre wie Integerist besser lesbar als int.
Stephen C
In vielen Fällen ist Integer nicht besser lesbar als int, und in diesen Fällen verwende ich immer int. Wenn ich weiß, dass eine bestimmte Variable NIEMALS null ist, verwende ich int, weil int, wie Sie bereits betont haben, etwas effizienter ist. In vielen Fällen ist es für einen anderen Programmierer jedoch einfacher, den Status einer Variablen zu verstehen, wenn ein Objekt verwendet wird, da es auf null initialisiert werden kann, um anzuzeigen, dass es nicht bereit ist. Wenn Sie beispielsweise einen nicht gespeicherten Datenbankeintrag mit einer eindeutigen inkrementellen numerischen ID haben, sollte diese ID 0, -1 oder null sein, bevor ihr eine gültige ID zugewiesen wird? In diesem Fall sind Objekte besser.
Pstanton
in Bezug auf die Leistung - In besonderen Fällen kann der Leistungseinbruch erheblich sein, dh wenn Sie eine Vielzahl dieser Objekte sehr schnell erstellen oder wenn sich viele, viele, viele von ihnen über einen bestimmten Zeitraum aufbauen. Ich würde jedoch erwarten, dass ein anständiger Programmierer diese Sonderfälle entweder vermeiden oder entsprechend ändern kann. Ich habe nie gesagt, dass es NIE bedeutsam ist, aber im Allgemeinen ist es nicht so.
Pstanton
12

Wenn meine Klassenmitglieder Wrapper-Variablen sind, sind meiner Meinung nach keine Standardwerte erforderlich, was ein entwicklerfreundliches Verhalten ist.

1.

class Person {
   int SSN ; // gets initialized to zero by default 
}

2.

class PersonBetter {
  Integer SSN; //gets initialized to null by default
}

Im ersten Fall können Sie den SSN-Wert nicht uninitialisieren. Es kann weh tun, wenn Sie nicht überprüfen, ob der Wert festgelegt wurde, bevor Sie versuchen, ihn zu verwenden.

Im zweiten Fall können Sie die SSN mit null initialisieren. Dies kann zu NullPointerException führen, ist jedoch besser, als unwissentlich Standardwerte (Null) als SSN in die Datenbank einzufügen, wenn Sie versuchen, diese zu verwenden, ohne das SSN-Feld zu initialisieren.

Cody
quelle
3
Das Builder-Muster soll dies umgehen. In diesem Szenario wird PersonBuildereine Ausnahme ausgelöst, wenn die SSN nicht festgelegt wurde, bevor "build" aufgerufen wird, um die PersonInstanz abzurufen. Ich denke, diese Art von Dingen ist übertrieben, aber es ist das, was die Java-Sprache für richtige Muster fördert.
Sandy Chapman
8

Ich würde die Wrapper-Typen nur verwenden, wenn Sie müssen.

Wenn Sie sie verwenden, gewinnen Sie nicht viel, abgesehen von der Tatsache, dass sie es sind Objects.

Und Sie verlieren Overhead bei der Speichernutzung und der Zeit, die Sie für das Boxen / Entpacken aufgewendet haben.

jjnguy
quelle
4
Sie gewinnen vielleicht nicht viel, aber Sie verlieren auch nicht viel. es sei denn, Sie laufen auf einem Palm-Piloten der 90er Jahre.
Pstanton
Die Tatsache, dass sie Objekte sind, gibt ihnen auch viel mehr Kontext und Kapselung als als einfaches Primitiv. Je nachdem, wofür diese Grundelemente bestimmt sind und wo sie verwendet werden, können Sie tatsächlich viel gewinnen.
aberrant80
4

Praktisch war ich auf eine Situation gestoßen, in der die Verwendung der Wrapper-Klasse erklärt werden kann.

Ich habe eine Serviceklasse erstellt, die eine long Typvariablen erstellt

  1. Wenn die Variable vom Typ ist long- wenn sie nicht initialisiert wird, wird sie auf 0 gesetzt -, ist dies für den Benutzer verwirrend, wenn sie in der GUI angezeigt wird
  2. Wenn die Variable vom Typ ist Long- wenn sie nicht initialisiert ist, wird sie auf gesetztnull - wird dieser Nullwert nicht in der GUI angezeigt.

Dies gilt Booleanauch dann, wenn Werte bei Verwendung von Grundelementen verwirrender sein können boolean(da der Standardwert false ist).

Mohamed Afzal
quelle
3

Sammlungen sind der typische Fall für einfache Java-Wrapper-Objekte. Sie können dem Wrapper jedoch eine spezifischere Bedeutung im Code (Wertobjekt) geben.

IMHO gibt es fast immer einen Vorteil, Wertobjekte zu verwenden, wenn es um Lesbarkeit und Pflege des Codes geht. Das Umschließen einfacher Datenstrukturen in Objekte, wenn sie bestimmte Verantwortlichkeiten haben, vereinfacht häufig den Code. Dies ist im domänengesteuerten Design sehr wichtig .

Es gibt natürlich das Leistungsproblem, aber ich neige dazu, dies zu ignorieren, bis ich die Möglichkeit habe, die Leistung mit geeigneten Daten zu messen und gezielter auf den Problembereich zu reagieren. Es ist möglicherweise auch einfacher, das Leistungsproblem zu verstehen, wenn der Code ebenfalls leicht zu verstehen ist.

Mattias Holmqvist
quelle
3

Die Leistung von Anwendungen, die von numerischen Berechnungen dominiert werden, kann von der Verwendung von Grundelementen stark profitieren.

Bei primitiven Typen wird der Operator == verwendet. Für den Wrapper wird jedoch bevorzugt die Methode equals () aufgerufen.

"Primitive Typen gelten als schädlich", weil sie "prozedurale Semantik" zu einem ansonsten einheitlichen objektorientierten Modell mischen.

Viele Programmierer initialisieren Zahlen mit 0 (Standard) oder -1, um dies anzuzeigen. Je nach Szenario kann dies jedoch falsch oder irreführend sein.

loknath
quelle
1

Wenn Sie Sammlungen verwenden möchten, müssen Sie Wrapper-Klassen verwenden.

Primitive Typen werden für Arrays verwendet. Außerdem, um Daten darzustellen, die kein Verhalten haben, z. B. einen Zähler oder eine boolesche Bedingung.

Seit dem Autoboxing ist die Grenze, wann Primitive oder Wrapper verwendet werden sollen, ziemlich verschwommen.

Denken Sie jedoch daran, dass Wrapper Objekte sind, sodass Sie alle ausgefallenen Java-Funktionen erhalten. Sie können beispielsweise Reflexion verwenden, um ganzzahlige Objekte zu erstellen, jedoch keine int-Werte. Wrapper-Klassen haben auch Methoden wie valueOf.

Tom
quelle
Außer Sammlungen sollte ich keine Wrapper-Klassen verwenden? Wie wäre es mit einer gewöhnlichen Deklaration wie Integer i = new Integer (10); Ist es gut so zu machen?
Gopi
Mit Autoboxing können Sie Integer i = 10 ausführen.
Tom
1
Nein, Sri. Wenn Sie nicht die Anforderung haben, dass ich ein Objekt bin, machen Sie es nicht zu einem.
Matthew Flaschen
Autoboxing entpackt das oben deklarierte i zu int i = 10 oder Integer i = 10?
Gopi
3
int pi = neue Ganzzahl (10); funktioniert. Ganzzahl oi = 10; funktioniert. int ni = null; funktioniert nicht Das LHS wird in das konvertiert, was das RHS erfordert.
Pstanton
0

Wenn Sie einen Werttyp erstellen möchten. So etwas wie eine ProductSKU oder ein AirportCode.

Wenn ein primitiver Typ (Zeichenfolge in meinen Beispielen) Gleichheit definiert, möchten Sie Gleichheit überschreiben.

Chris Missal
quelle
5
Zeichenfolge ist kein Primitiv
Pstanton
2
Es gibt immer noch gute Gründe, einen Werttyp zu umbrechen, der eine Zeichenfolge als Basisobjekt enthält.
Chris Missal
Ihre Antwort macht einfach keinen Sinn. Ich bin mir nicht sicher, was du sagst. Ich stimme Ihrem Kommentar jedoch zu. Wrapper-Klassen sind eine gute Idee, wenn sie die Lesbarkeit verbessern.
Pstanton
Werttypen oder Wertobjekte sollten erstellt und unveränderlich sein. Zum Beispiel wäre es nicht sinnvoll, ein "CountryCode" -Objekt wie folgt zu erstellen: new CountryCode ("USA") und dann auf die gleiche Weise ein anderes Objekt zu erstellen, wo sie später unterschiedlich sind. Sie sind zunächst nur Zeichenfolgen, aber sie haben eine Bedeutung hinter sich. Durch die Verwendung von Zeichenfolgen können Sie diese ändern (indem Sie mehr Daten anhängen usw.), aber sie sind nicht mehr gleich. In diesem Artikel finden Sie eine bessere Beschreibung dessen, was ich zu erklären versuche :) Ich hoffe, dies macht Sinn c2.com/cgi/wiki?ValueObject
Chris Missal
0

Primitive Werte in Java sind kein Objekt. Um diese Werte als Objekt zu bearbeiten, stellt das Paket java.lang eine Wrapper-Klasse für jeden der primitiven Datentypen bereit.

Alle Wrapper-Klassen sind endgültig. Das Objekt aller Wrapper-Klassen, die initiiert werden können, ist unveränderlich. Dies bedeutet, dass der Wert im Wrapper-Objekt nicht geändert werden kann.

Die void- Klasse wird zwar als Wrapper-Klasse betrachtet, umschließt jedoch keine primitiven Werte und ist nicht initiierbar. Es gibt keinen öffentlichen Konstruktor, sondern nur ein Klassenobjekt, das das Schlüsselwort void darstellt.

Ahmad Sayeed
quelle