Titel   Inhalt   Suchen   Index   DOC  Handbuch der Java-Programmierung, 7. Auflage
 <<    <     >    >>   API  Kapitel 11 - OOP IV: Verschiedenes

11.2 Wrapper-Klassen



11.2.1 Vordefinierte Wrapper-Klassen

Zu jedem primitiven Datentyp in Java gibt es eine korrespondierende Wrapper-Klasse. Diese kapselt die primitive Variable in einer objektorientierten Hülle und stellt eine Reihe von Methoden zum Zugriff auf die Variable zur Verfügung. Zwar wird man bei der Programmierung meist die primitiven Typen verwenden, doch gibt es einige Situationen, in denen die Anwendung einer Wrapper-Klasse sinnvoll sein kann:

Wrapper-Klassen existieren zu allen numerischen Typen und zu den Typen char und boolean:

Wrapper-Klasse Primitiver Typ
Byte byte
Short short
Integer int
Long long
Double double
Float float
Boolean boolean
Character char
Void void

Tabelle 11.1: Die Wrapper-Klassen

Instanzierung

Die Instanzierung einer Wrapper-Klasse kann meist auf drei unterschiedliche Arten erfolgen:

public Integer(int i)

public Integer(String s)
  throws NumberFormatException
  
public static Integer valueOf(int i)

public Long(long l)

public Long(String s)
  throws NumberFormatException

public static Long valueOf(long l)

public Float(float f)

public Float(double d)

public Float(String s)
  throws NumberFormatException

public static Float valueOf(float f)

public Double(double d)

public Double(String s)
  throws NumberFormatException

public static Double valueOf(double d)

public Boolean(boolean b)

public Boolean(String s)

public static Boolean valueOf(boolean b)

public Character(char c)

public static Character valueOf(char c)

Das in diesem Beispiel mehrfach verwendete Schlüsselwort throws deklariert Ausnahmen, die während der Methodenausführung auftreten können. Sie entstehen durch Programmfehler, undefinierte Zustände oder treten auf, wenn unvorhergesehene Ereignisse eintreten (Datei nicht verfügbar, Speicher erschöpft oder Ähnliches). Wir werden uns in Kapitel 13 ausführlich mit diesem Thema beschäftigen.

 Hinweis 

Rückgabe des Werts

Die meisten Wrapper-Klassen besitzen zwei Methoden, um den internen Wert abzufragen. Eine der beiden liefert ihn passend zum korrespondierenden Grundtyp, die andere als String. Der Name von Methoden der ersten Art setzt sich aus dem Namen des Basistyps und der Erweiterung Value zusammen, beispielsweise charValue, booleanValue oder intValue. Die numerischen Methoden intValue, longValue, floatValue und doubleValue stehen dabei für alle numerischen Wrapper-Klassen zur Verfügung.

public boolean booleanValue()
public char charValue()
public int intValue()
public long longValue()
public float floatValue()
public double doubleValue()

Der Name der Methode, die den internen Wert als String zurückgibt, ist toString. Diese Methode steht in allen Wrapper-Klassen zur Verfügung:

public String toString()

Ein einfaches Beispiel für die Anwendung der Wrapper-Klassen zeigt folgendes Listing:

001 /* Listing1105.java */
002 
003 public class Listing1105
004 {
005   public static void ohneAutoboxing(int arg)
006   {
007     Integer i = new Integer(arg);
008     int j = i.intValue() + 1;
009     System.out.println(i + " " + j);
010   }
011 
012   public static void main(String[] args)
013   {
014     ohneAutoboxing(17);
015   }
016 }
Listing1105.java
Listing 11.5: Anwendung der Wrapper-Klassen

Die Methode ohneAutoboxing (warum sie so heißt, wird später deutlich werden) erzeugt einen Integer-Wrapper i aus dem als Argument übergebenen int. Dieser wird in einen int zurückkonvertiert und nach Addition von 1 der Variablen j zugewiesen. Anschließend werden beide Werte ausgegeben:

17 18

Parsen von Strings

Neben der Möglichkeit, aus Strings Objekte zu erzeugen, können die meisten Wrapper-Klassen auch primitive Datentypen erzeugen. Dazu gibt es statische Methoden mit den Namen parseByte, parseInt, parseLong, parseFloat und parseDouble in den zugehörigen Klassen Byte, Integer, Long, Float und Double:

public static byte parseByte(String s)
  throws NumberFormatException

public static int parseInt(String s)
  throws NumberFormatException

public static long parseLong(String s)
  throws NumberFormatException

public static float parseFloat(String s)
  throws NumberFormatException

public static double parseDouble(String s)
  throws NumberFormatException

Konstanten

Die numerischen Wrapper-Klassen stellen Konstanten zur Bezeichnung spezieller Elemente zur Verfügung. So gibt es in jeder der Klassen Byte, Short, Integer, Long, Float und Double die Konstanten MIN_VALUE und MAX_VALUE, die das kleinste bzw. größte Element des Wertebereichs darstellen. In den Klassen Float und Double gibt es zusätzlich die Konstanten NEGATIVE_INFINITY, POSITIVE_INFINITY und NaN. Sie stellen die Werte minus unendlich, plus unendlich und undefiniert dar.

11.2.2 Call by Reference

Da Objektparameter im Gegensatz zu primitiven Typen per Referenz übergeben werden, wären Wrapper-Klassen prinzipiell geeignet, Methodenparameter per call by reference zu übergeben. Damit könnten Änderungen von primitiven Parametern an den Aufrufer zurückgegeben werden. In der Praxis funktioniert das allerdings nicht, denn alle vordefinierten Wrapper-Klassen sind unveränderlich (das wird auch als immutable bezeichnet).

Sollen primitive Typen per Referenz übergeben werden, bieten sich zwei Möglichkeiten an:

Beide Methoden sind nicht sehr elegant, werden aber in der Praxis mitunter benötigt. Das folgende Listing zeigt, wie es gemacht wird:

001 /* Listing1106.java */
002 
003 class IntWrapper
004 {
005   public int value;
006 
007   public IntWrapper(int value)
008   {
009     this.value = value;
010   }
011 }
012 
013 public class Listing1106
014 {
015   public static void inc1(IntWrapper w)
016   {
017     ++w.value;
018   }
019 
020   public static void inc2(int[] i)
021   {
022     ++i[0];
023   }
024 
025   public static void main(String[] args)
026   {
027     //Variante 1: Übergabe in einem veränderlichen Wrapper
028     IntWrapper i = new IntWrapper(10);
029     System.out.println("i = " + i.value);
030     inc1(i);
031     System.out.println("i = " + i.value);
032     //Variante 2: Übergabe als Array-Element
033     int[] j = new int[] {10};
034     System.out.println("j = " + j[0]);
035     inc2(j);
036     System.out.println("j = " + j[0]);
037   }
038 }
Listing1106.java
Listing 11.6: Call by Reference

11.2.3 Autoboxing und Autounboxing

Seit der J2SE 5.0 gibt es einen Mechanismus, der das automatische Ein- und Auspacken von primitiven Typen in und aus Wrapper-Klassen unterstützt. Dieses als Autoboxing bzw. Autounboxing (»automatisches Ein- und Auspacken«) bezeichnete Verfahren sorgt dafür, dass an vielen Stellen automatisch zwischen primitiven Typen und Wrapper-Objekten konvertiert wird. Erwartet eine Methode beispielsweise einen Integer-Wert als Argument, kann außer einem Integer auch direkt ein int übergeben werden; und er wird ohne Zutun des Entwicklers in einen gleichwertigen Integer konvertiert. Auch in umgekehrter Richtung funktioniert das, etwa wenn in einem arithmetischen Ausdruck ein double erwartet, aber ein Double übergeben wird.

Das Beispiel aus Listing 11.5 kann seit der J2SE 5.0 wie folgt vereinfacht werden:

001 /* Listing1107.java */
002 
003 public class Listing1107
004 {
005   public static void mitAutoboxing(int arg)
006   {
007     Integer i = arg;
008     int j = i + 1;
009     System.out.println(i + " " + j);
010   }
011 
012   public static void main(String[] args)
013   {
014     mitAutoboxing(new Integer(17));
015   }
016 }
Listing1107.java
Listing 11.7: Autoboxing und Autounboxing

Die Einführung des Autoboxings und Autounboxings hat eine Vielzahl von Auswirkungen auf die Java-Sprachspezifikation gebracht. Primitive Typen und Wrapper-Objekte können nun in weiten Bereichen fast gleichberechtigt benutzt werden. Die mitunter kritisierte und in manchen reinen OO-Sprachen (wie etwa Smalltalk) nicht vorhandene Unterscheidung zwischen beiden Gruppen ist für die meisten praktischen Belange nun irrelevant.

So wird das Autoboxing etwa bei Zuweisungen und Methodenaufrufen angewandt, wenn ein Wrapper-Objekt erwartet wird, aber nur ein primitiver Wert zur Verfügung steht. Umgekehrt wird ein entsprechender Wrapper bei Bedarf automatisch ausgepackt, wenn ein primitiver Wert erwartet, aber ein Wrapper-Objekt übergeben wird. Auch innerhalb von Ausdrücken können Wrapper-Objekte meist nahtlos anstelle von (und zusammen mit) primitiven Werten verwendet werden. Ausnahme sind einige verändernde Operatoren wie ++ und -- oder die kombinierten Zuweisungsoperatoren += oder -=. Wegen der Nebeneffekte können diese nicht auf (die per Definition unveränderlichen) Wrapper-Objekte angewendet werden.

Das obige Beispiel wirkt zugegebenermaßen etwas konstruiert. Der wahre Nutzen des Autoboxings und Autounboxings kommt vor allem in Synergie mit der erweiterten for-Schleife und den typisierten Collections zum Tragen. Beispiele finden sich etwa in Listing 16.10 oder Listing 16.12.

 Hinweis 

In Abschnitt 52.2.6 gehen wir noch einmal auf das Thema Autoboxing ein, dort unter Performance-Gesichtspunkten.


 Titel   Inhalt   Suchen   Index   DOC  Handbuch der Java-Programmierung, 7. Auflage, Addison Wesley, Version 7.0
 <<    <     >    >>   API  © 1998, 2011 Guido Krüger & Heiko Hansen, http://www.javabuch.de