Wrapper-Klassen
Wrapper-Klassen
- Primitive Typen sind keine Objekte
- An manchen Stellen muss man aber Objekte anstatt primitiver Typen verwenden
- Wrapper-Klassen (wrapper classes) stellen für jeden primitiven Typ einen passenden Klassen-Typ zur Verfügung
Primitiver Typ | Wrapper |
---|---|
boolean | Boolean |
byte | Byte |
char | Character |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
Die Wrapper (Einwickler) haben ihren Namen von der Tatsache, dass sie sich um die primitiven Typen herum legen und sie als Objekt umschließen. Man beachte die Asymmetrie bei int
/Integer
und char
/Character
: Normalerweise entspricht der Name des Wrappers dem Namen des primitiven Typs nur mit Großbuchstaben. Bei int
und char
ist dem aber nicht so.
Alle Wrapper enthalten Konvertierungsmethoden in beide Richtungen, d. h. vom primitiven Typen zum Objekt und vom Objekt zum primitiven Typen.
Weiterhin finden sich in den Wrappern wichtige Konstanten, z. B. Integer.MAX_INT
als maximaler Wert, den ein int
annehmen kann.
Alle Wrapper sind als unveränderliche Objekte (immutable Objects) konstruiert. Es kann daher aus Performance-Gründen sinnvoll sein, ein und dasselbe Wrapper-Objekt mehrfach zu verwenden. Bei Boolean
sollte man normalerweise überhaupt kein Wrapper-Objekt neu anlegen, sondern einfach die beiden vordefinierten Objekte Boolean.TRUE
und Boolean.FALSE
verwenden.
Beispiel: Wrapper
int i = 5;
Integer i1 = new Integer(i);
int j = i1.intValue();
Integer i2 = Integer.valueOf("42");
int i3 = Integer.parseInt("42");
Das Beispiel zeigt das Anlegen eines int
-Wrappers über den Konstruktor von Integer
und das Auslesen des Wertes aus dem Wrapper mit der Methode intValue()
. Zusätzlich sind zwei Methoden gezeigt, um aus einem String einen int
-Wert bzw. ein Integer
-Objekt zu erzeugen. Die Verwendung des Konstruktors ist inzwischen nicht mehr empfohlen, sondern man sollte sich auf das Autoboxing stützen.
Autoboxing
Seit Java 5 kann der Compiler automatisch zwischen primitiven Typen und Klassen-Typen konvertieren, man spricht hier von Autoboxing
Integer k = 5;
int j = k;
Object o = true;
boolean b = new Boolean(true);
Long l = 0L;
for (int i = 0; i < Integer.MAX_VALUE; i++) {
l += i;
}
Der Java-Compiler führt das Autoboxing in beiden Richtungen durch, d. h. es gibt sowohl ein autoboxing als auch ein auto-unboxing.
Die untere Schleife ist mit einem erheblichen Performanceproblem belastet.
Dadurch, dass man statt long
Long
geschrieben hat, findet bei jedem Schleifendurchlauf ein Autoboxing statt. Statt also einfach eine long
-Variable zu erhöhen, werden hier mehrere Milliarden Long
-Objekte erzeugt und wieder zerstört. Die Geschwindigkeit ist daher um Größenordnungen geringer, ohne dass man dies am Source-Code sehen könnte (bis auf das große „L“).
Praxistipp: Autoboxing und ==
- Durch Autoboxing werden primitiven Typen zu Objekten. Damit gelten aber die Regeln für
equals()
und==
- Ein Vergleich von Wrapper-Typen mit
==
ist immer falsch
public static boolean compare(Integer i1, Integer i2) {
return i1 == i2;
}
public static void main(String[] args) {
int i1 = 10;
int i2 = 10;
System.out.println(i1 + " == " + i2 + " : " + compare(i1, i2));
i1 = 2000;
i2 = 2000;
System.out.println(i1 + " == " + i2 + " : " + compare(i1, i2));
}
Ausgabe
10 == 10 : true
2000 == 2000 : false
Die Ausgabe des Programms ist erstaunlich. Beim Wert 2000 sieht man deutlich, dass durch das Autoboxing der int
-Variablen zwei unterschiedliche Objekte entstanden sind, die nicht damit nicht identisch sind. Daher liefert der ==-Vergleich false
zurück.
Aber warum passiert das nicht bei dem Wert 10?
Die Klasse Integer
nimmt eine Optimierung vor: für alle Werte kleiner 128 werden keine neuen Integer
-Objekte erzeugt, sondern aus einem Cache einfach immer wieder dieselbe Objektreferenz zurückgeliefert. Dies ist möglich, da Integer unveränderlich (immutable) ist und daher für den Verwender nicht unterscheidbar ist, ob er zwei Referenzen auf zwei Objekte oder zwei Referenzen auf dasselbe Objekt benutzt (zumindest so lange er nicht mit == explizit darauf testet). Das hier von Integer angewandte Entwurfsmuster ist das sogenannte Fliegengewicht) (flyweight).