06.06 Wrapper-Klassen
Wrapper-Klassen sind Klassen um einen primitiven Datentyp (siehe Kapitel 02.03 Primitive Datentypen) als Objekt zu behandeln. Somit können primitive Datentypen durch ihre Wrapper-Klassen bspw. Methoden als Parameter übergeben werden, die ansonsten nur Objekte erwarten. Auch eine Definition als Generic wird so möglich.
Sie haben bereits mit Wrapper-Klassen gearbeitet. Sehen Sie sich hierzu noch mal Kapitel 03.06 Primitive Datentypen und Strings an. Die meisten Wrapper-Klassen haben ähnliche Eigenschaften, weshalb die Gemeinsamkeiten aller oder zumindest vieler Wrapper im nachfolgenden Abschnitt erklärt werden. Gesondert behandelt werden dann nur noch die Klassen Character
, Integer
, Long
und die Fließkommazahlen Double
und Float
.
Gemeinsamkeiten von Wrapper-Klassen
Eine Wrapper-Klasse heißt genauso wie der zugehörige primitive Datentyp (ausgenommen int
und char
, hierfür lauten die Wrapper Integer
und Character
) und hat den Konstruktor WrapperKlasse(primitiverDatentyp)
zur Verfügung, um den zu repräsentierenden, primitiven Datentyp gleich bei der Initialisierung zu übergeben. Auch findet sich in allen Wrapper-Klassen (außer Character
) der Konstruktor WrapperKlasse(String)
, der den String
in einen primitiven Datentyp umwandelt.
Integer i = new Integer(1234); Boolean b = new Boolean("true"); Character c = new Character('A'); Double d = new Double(234.65);
Eine statische Methode um einen String
direkt in einen primitiven Datentyp umzuwandeln kennen Sie bereits. Sie steht allen Wrappern (außer Character
) zur Verfügung und beginnt immer mit parse gefolgt vom Namen des primitiven Datentyps. Es gibt allerdings noch eine andere Methode, die fast das Selbe erledigt: valueOf
. Mit valueOf
wird jedoch kein primitiver Datentyp zurückgeliefert, sondern eine Instanz der Wrapper-Klasse (welche aber via Autounboxing wieder in einen primitiven Datentyp gewandelt werden kann). Generell sollten Sie valueOf
verwenden, wenn Sie eine Wrapper-Klasse benötigen, und parseXyz
, wenn Sie einen primitiven Datentyp benötigen.
Boolean bool = Boolean.valueOf("true"); Byte b = Byte.valueOf("-5"); Short s = Short.valueOf("300"); int i = Integer.parseInt("50000";); Long l = Long.valueOf("12345678"); float f = Float.parseFloat("32.53"); Double d = Double.valueOf("0.123456789");
Dieser Methode kann bei statischer Verwendung in jedem Fall (diesmal auch bei Character
) der primitive Datentyp übergeben werden. Erzeugt wird ein neues Objekt des Wrappers mit dem angegeben Wert.
Die Objektmethode toString
wandelt den aktuellen Wert des Wrappers in einen String
, die Klassenmethode toString(primitiverDatentyp)
wandelt einen primitiven Datentyp direkt in einen String
um.
Um die Wrapper-Klasse wieder als primitiven Datentyp zu erhalten, ruft man primitiverDatentypValue()
auf. Dies funktioniert bei allen Wrappern. Die Wrapper für Zahlen (Byte, Short, Integer, Long, Float
und Double
) erben allesamt von Number
und implementieren deshalb noch zusätzlich Methoden um den Wert in alle anderen primitiven Datentypen umzuwandeln.
Integer i = new Integer(1234); Boolean b = new Boolean("true"); Character c = new Character('A'); Double d = new Double(234.65); System.out.println(d.doubleValue()); System.out.println(i.byteValue()); System.out.println(c.charValue()); System.out.println(b.booleanValue());
Alle Wrapper-Klassen haben vier identisch benannte Konstanten (außer Boolean
). Diese repräsentieren jeweils den höchsten (MAX_VALUE
) und den niedrigsten (MIN_VALUE
) Wert, den dieser Typ annehmen kann (Bei Float
und Double
ist dieser Wert aufgrund der Fließkommadarstellung dennoch positiv. MIN_VALUE
stellt hier vielmehr die Zahl dar, die am nähesten an der 0 ist), die Größe des Datentyps (SIZE
) und den eigentlichen Typ des primitiven Datentyps in Form der Klasse Class
mit der Wrapper-Klasse als Generic (TYPE
). Boolean
kennt hingegen nur seinen TYPE
, besitzt dafür aber noch zwei statische Objekte von sich selbst – einmal als Repräsentation für true
(TRUE
), und die andere für false
(FALSE
).
Als letzte, nennenswerte Gemeinsamkeit findet man in allen Wrappern eine sinnvolle Implementierung der Methoden equals
, hashCode
(siehe Kapitel 04.03.11 Besondere Methoden) und compareTo
.
compareTo
resultiert aus der Implementierung des InterfacesComparable
und vergleicht das aktuelle Objekt mit einem anderen Objekt gleichen Typs.Comparable
wird erst zu einem späteren Zeitpunkt in diesem Buch besprochen
Integer und Long
Diese beiden Wrapper-Klassen haben noch ein paar Methoden mehr als die anderen Zahlen-Wrapper. Darunter finden sich unter anderem Methoden um einen primitiven Datentyp (toBinaryString()
), hexadezimal (toHexString
) oder oktal (toOctalString()
) darzustellen. Auch stehen diverse weitere Methoden zur Bit-Manipulation bereit. Eine Auflistung aller Methoden finden Sie natürlich wieder in der JavaDoc zu den beiden Klassen.
Erwähnenswert ist noch die erweiterten parse
-, und toString
-Funktion von Integer
und Long
. Diesen kann noch ein weiterer Parameter als int
übergeben werden. Hierbei handelt es sich um die Zahlenbasis, auch radix genannt. So ist es z. B. möglich binäre, hexadezimale oder oktale Strings in einen primitiven Datentyp oder umgekehrt zu wandeln. Durch die Flexibilität der Zahlenbasis sind aber auch ungewöhnliche Konvertierungen möglich:
System.out.println(Integer.toString(1234, 5)); System.out.println(Integer.parseInt("14414", 5)); System.out.println(Integer.toString(1234, 11)); System.out.println(Integer.parseInt("a22", 11)); System.out.println(Integer.toString(1234, 36)); System.out.println(Integer.parseInt("ya", 36));
Float und Double
Bei Float
und Double
sind vor allem die zusätzlichen Konstanten und die dazugehörigen Methoden interessant. So haben diese beiden Klassen unter anderem (auch hier finden Sie eine vollständige Auflistung in der JavaDoc) noch die Konstanten NaN
(keine Nummer), NEGATIVE_INFINITY
(negative Unendlichkeit) und POSITIVE_INFINITY
(positive Unendlichkeit). Es ist also möglich Fließkommazahlen auch als abstrakte Zahlen (keine Zahl, Unendlichkeit) darzustellen. Diese Werte werden durch eine bestimmte Bit-Kombination erzeugt (NEGATIVE_INFINITY = Float.intBitsToFloat(0xff800000) / Double.longBitsToDouble(0xfff0000000000000L), POSITIVE_INFINITY = Float.intBitsToFloat(0x7f800000) / Double.longBitsToDouble(0x7ff0000000000000L), NaN = Float.intBitsToFloat(0x7fc00000) / Double.longBitsToDouble(0x7ff8000000000000L)
).
Mit den Methoden isNaN
und isInfinite
kann dieser Zustand überprüft werden. Selbstverständlich funktioniert aber auch der normale Vergleich:
if (doub == Double.NaN) { ... } else if (doub == Double.NEGATIVE_INFINITY || doub == Double.POSITIVE_INFINITY) { ... }
Mit den Klassenmethoden doubleToLongBits
bzw. floatToIntBits
und longBitsToDouble
bzw. intBitsToFloat
können Fließkommazahlen in ihre Ganzzahlrepräsentation und umgekehrt umgewandelt werden.
Character
Der Wrapper für chars
ist sehr viel Umfangreicher als die restlichen Wrapper. Verschaffen Sie sich deshalb bitte einen eigenen Überblick in der JavaDoc. Einige ausgewählte Methoden werde ich Ihnen aber auch hier vorstellen (beachten Sie, dass die meisten Methoden statischer Natur sind):
toUpperCase / toLowerCase / isUpperCase / isLowerCase
Mit diesen Methoden können Sie ein Zeichen in Groß- (toUpperCase
) oder Kleinschreibung (toLowerCase
) umwandeln, oder überprüfen, ob ein Zeichen klein (isLowerCase
) oder groß (isUpperCase
) ist.
Character.isUpperCase('A'); char c = 'c'; c = Character.toUpperCase(c);
isDigit / isLetter / isLetterOrDigit
Wenn Sie überprüfen wollen, ob ein Zeichen eine Zahl (isDigit
) ein Buchstabe (isLetter
) oder ein Buchstabe oder eine Zahl (isLetterOrDigit
) ist, sollten Sie diese Methoden verwenden.
Character.isDigit('8'); Character.isLetter('A'); Character.isLetterOrDigit('*');
isWhitespace
Hiermit kann überprüft werden, ob es sich beim übergebenen Zeichen um einen „freien Raum“ handelt, wie es z. B. bei einem Leerzeichen, Tabulator oder Zeilenumbruch der Fall ist.
System.out.println(Character.isWhitespace('\t')); System.out.println(Character.isWhitespace('\n')); System.out.println(Character.isWhitespace(' '));
Eine Frage zu NaN, POSITIVE_INFINITY und NEGATIVE_INFINITY:
Wie das ganze gespeichert wird, will ich eigentlich gar nicht wissen. Nur ist mir aufgefallen, dass die Benutzung dieser Konstanten keinen Wert zurückgibt, sondern seltsamerweise ein String; „NaN“, „Infinity“ und „-Infinity“.
Nun meine Frage: Wie war das möglich? Gab es da eine spezielle Speichermethode oder wurde das von Java in der VM spezialisiert, dass diese Bitfolge so ausgegeben wird?
Wie das gespeichert wird, kann man ganz einfach im Java Code nachlesen:
Wie das exakt umgewandelt wird, kann ich leider nicht sagen. Ich gehe aber auch davon aus, dass die Bit-Folge automatisch bei einer Ausgabe umgewandelt wird. Um einen String handelt es sich dabei aber keinesfalls.
Grüße
Stefan
Tjaa… Genau das ist leider ein Problem bei mir: Ich arbeite ausschliesslich mit Eclipse. Die Javadocs, die angezeigt werden, sind zwar hilfreich, nur möchte ich oft genaueres darüber wissen, wie z.B. ob die equals()-Methode überschrieben wurde, wie Random die Klasse Random wirklich ist usw.
Nur wird mir jedesmal, wenn ich es mir anschauen will, gesagt, dass kein Source-Code gefunden wurde. Um das zu beheben soll man den Source „attachen“, nur habe ich leider keine Ahnung, was das bedeutet oder wie man es macht. Deswegen würde ich mich über eine Antwort freuen.
Gruss,
Cyrill
Hallo Cyrill,
den Sourcecode findest du im JDK Installationsordner unter src.zip.
Grüße
Stefan