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 Interfaces Comparable 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(' '));

4 Replies to “06.06 Wrapper-Klassen”

  1. Cyrill Brunner

    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?

  2. Stefan Kiesel

    Wie das gespeichert wird, kann man ganz einfach im Java Code nachlesen:

        /**
         * A constant holding the positive infinity of type
         * {@code double}. It is equal to the value returned by
         * {@code Double.longBitsToDouble(0x7ff0000000000000L)}.
         */
        public static final double POSITIVE_INFINITY = 1.0 / 0.0;
    
        /**
         * A constant holding the negative infinity of type
         * {@code double}. It is equal to the value returned by
         * {@code Double.longBitsToDouble(0xfff0000000000000L)}.
         */
        public static final double NEGATIVE_INFINITY = -1.0 / 0.0;
    
        /**
         * A constant holding a Not-a-Number (NaN) value of type
         * {@code double}. It is equivalent to the value returned by
         * {@code Double.longBitsToDouble(0x7ff8000000000000L)}.
         */
        public static final double NaN = 0.0d / 0.0;

    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

  3. Cyrill Brunner

    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

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.