Wrapperklassen

Aus Programmieren-Wiki
🚧 Diese Seite befindet sich in Bearbeitung 🚧

Beschreibung

Als Wrapper bezeichnet man ein Objekt, das ein anderes Objekt verpackt, um dessen Zugriff oder Verhalten zu kontrollieren. Wird in Java von Wrapperklassen gesprochen, sind damit die Klassen gemeint, die primitive Datentypen in Objekte (Referenzdatentypen) verpacken. Zu jedem der acht primitiven Datentypen stellt Java eine Wrapperklasse bereit, die ohne import verwendet werden:

Primitiver Datentyp Wrapperklasse
boolean Boolean
byte Byte
short Short
char Character
int Integer
long Long
float Float
double Double

Primitive Datentypen können durch eine Zuweisung in Wrapperklassen ein- und ausgepackt (auto-boxing und auto-unboxing) werden:

Integer foo = 123;	//auto-boxing
int bar = foo;		//auto-unboxing
Wie alle Referenzdatentypen können auch Instanzen von Wrapperklassen den Wert null annehmen. Bei primitiven Datentypen ist das nicht möglich. Bei dem Versuch, eine null-Referenz auszupacken, wird eine NullPointerException geworfen.

Richtige Verwendung

  • Parsen

Häufig liegen Werte von primitiven Datentypen als String vor, z. B. nach Benutzereingaben. Damit diese sicher in den primitiven Datentyp umgewandelt werden können, stellt jede Wrapperklasse, außer Character, eine statische parse*() Methode zur Verfügung. Der * representiert dabei den primitiven Datentyp.

Negativbeispiel

Das folgende Programm versucht "123" in einen int zu überführen.

char[] characters = "123".toCharArray();
int number = 0;
for (char character : characters) {
    number = number * 10 + (character - '0');
}
System.out.println(number);
Die Lösung ist ineffizient, ignoriert einen möglichen Integer-Überlauf und berechnet einen falschen Wert, wenn character keine Zahl zwischen 0-9 ist. Sie sollte daher auf keinen Fall verwendet werden.

Positivbeispiel

int number = 0;
try {
    number = Integer.parseInt("123");
} catch (NumberFormatException e) {
    System.out.println("Error, " + e.getMessage());
}
System.out.println(number);
Dieser Ansatz verwendet die bereitgestellte Integer.parseInt()-Methode, die intern bereits alle möglichen Fehler abdeckt. Außerdem ist diese Lösung deutlich verständlicher. Die Ausnahme NumberFormatException sollte immer abgefangen werden, mehr dazuhier.
  • Primitive Datentypen vor Wrapperklassen

Negativbeispiel

Integer[] values = new Integer[] { 1, 2, 3, 4 };
Integer sum = 0;
for (Integer value : values) {
    sum += value;
}
System.out.println(sum);
Da das Array nur Ganzzahlen enthält ist es hier unnötig, die Wrapperklasse Integer zu verwenden. Das selbe Ergebnis kann auch mit dem primitiven int erzielt werden. Gleiches gilt auch für einfache Variablen

Positivbeispiel

int[] values = new int[] { 1, 2, 3, 4 };
int sum = 0;
for (int value : values) {
    sum += value;
}
System.out.println(sum);
Jetzt wird nur noch int verwendet. Das ist performanter und verbraucht weniger Speicherplatz.
  • Datenstrukturen

In generisch typparametrisierten Datenstrukturen (z. B. Collections) ist es nicht möglich, primitive Datentypen zu verwenden. Hier werden Wrapperklassen benötigt.

Positivbeispiel

Die Methode getData() gibt eine Liste von Double-Werten zurück, die auch null enthalten kann.

List<Double> values = getData();
double highest = 0;
for (Double value : values) {
    if (value != null && value > highest) {
        highest = value;
    }
}
System.out.println(highest);
Die Schleifenvariable value muss vom Typ Double sein, um die Möglichkeit von null abzudecken. Die Variable highest kann ein primitiver double sein, da nur der numerische Wert relevant ist. Bevor value zu highest zugewiesen wird, wird überprüft, dass sie nicht null ist.
  • Vergleiche mit equals()

Bei Wrapperklasseninstanzen handelt es sich nicht mehr um primitive Datentypen. Eine Überprüfung mit dem einfachen Gleichheitsoperator (==) kann ein unerwartetes Ergebnis bringen. Um inhaltliche Gleichheit von zwei Objekten zu prüfen, muss die equals() Methode verwenden werden.

Negativbeispiel

Integer foo = 128;
Integer bar = 128;
System.out.println(foo == bar);
Es wird false ausgegeben, obwohl beide Instanzen den selben Wert beinhalten.

Positivbeispiel

Integer foo = 128;
Integer bar = 128;
System.out.println(foo.equals(bar));
Nun wird korrekt auf inhaltliche Gleichheit geprüft und es wird true ausgegeben.


Grundsätzlich sollten Instanzen von Wrapperklassen nur dann verwendet werden, wenn primitive Datentypen nicht möglich sind! Primitive Datentypen sind schneller und resourcenschonender.