68. Wrapper & Auto-(Un) Boxing
Jeden primitiven Datentyp kann man ‘wrappen’
Die Wrapper befinden sich in deren einzelnen Klassen (8 Stück): Integer, Character, Byte, Short, Long, Double, Float, Boolean
Wrapper-Objekte besitzen Instanzvariable. einen Konstruktor, einen Getter aber keinen Setter -> Wrapper-Objekte sind Immutable
Integer integer = new Integer("100") ;
- Integer(String s):
Es wird ein String abgegeben und der Integer-Wert wird daraus herausgezogen (z.B. “100”). Ist dies zur Laufzeit nicht möglich, so gibt es eine Exception oder es wird ein Standardwert verwendet (z.B. false bei Boolean) -> gilt für alle Wrapper-Klassen
Die Wrapper-Klassen bieten viele Methoden -> in API nachschauen
Hint
.hashCode() nützlich um den HashCode eines eigenen Objekts möglichst
einzigartig zu machen:
@Override
public int hashCode(){
return getLeistung() + new Integer (1*AnzahlTueren).hashCode() + getHersteller().hashCode();
}
Wrapper packen einen primitiven Datentyp in ein Objekt
essentiell bei generischen Datenstrukturen
Liste<Integer>liste = new Liste<Integer>(100);
liste.add(new Integer(25));
- Auto Boxing:
der Compiler kann primitive Datentypen selbstständig in entsprechende Wrapper-Objekte umwandeln
- Auto Un-Boxing:
der Compiler kann Wrapper-Objekte selbstständig in entsprechende primitive Datentypen umwandeln
Man kann also auch schreiben:
Liste<Integer>liste = new Liste<Integer>(100);
liste.add(25);
Der Compiler erkennt automatisch, dass er den primitiven Datentyp in einen Wrapper packen muss, um ihn der Liste hinzuzufügen, daher kann man schlicht den primitiven Typ angeben.
Genauso kann ein Abruf eines Listeneintrags wandelt der Compiler das Wrapper-Objekt
automatisch in den primitiven Datentyp um (ruft dazu die Integer.intValue()
Methode auf): i = liste.get(0);
Es können auch Rechenoperationen auf Wrapper-Objekte angewandt werden:
Double d1 = new Double(1.4);
Double d2 = new Double(2.4);
Double d3 = d1 + d2;
Hier passiert ebenso automatischen Boxing und Un-Boxing.
Attention
Vergleich von Wrapper-Objekten
Integer i1 = new Integer(50);
Integer i2 = new Integer(50);
System.out.println(i1 >= i2); // -> TRUE
// true, weil die Werte gleich sind
System.out.println(i1 == i2); // -> FALSE
// false, da bei Integer in unterschiedlichen Objekten abgelegt sind
//(== bedeutet bei Objekten Identität, nicht Wert)
Integer i1 = 50;
Integer i2 = 50;
System.out.println(i1 == i2);-> TRUE
// true, weil Integer Objekte ebenso einen Constant Pool haben, wodurch
Objekte mit gleichem Inhalt nicht erneut abgelegt werden.
Integer i1 = 200;
Integer i2 = 200;
System.out.println(i1 == i2); // -> FALSE
//Jedoch umfasst dieser nur den Wertebereich von -128 bis +127 😉
Faustregel
Bei größeren Vergleichen und Berechnungen verhindern, dass Auto-Boxing und Un-Boxing verwendet wird, da man sehr genau aufpassen muss, wann dies geschieht und wann nicht.
BigInteger & BigDecimal
nur vom Speicher begrenzte Höhe des Wertes (nicht die typischen Grenzen)
möglich, da die Klasse Werte intern als String speichert
wird z.B. für sehr große Zahlen und genaueste Berechnungen verwendet (Double hat “nur” 64-Bit Genauigkeit und muss irgendwann runden)
Fehler passieren, wenn mit bereits gerundeten Werten weitergerechnet wird:
for (double d = 0; d <= 1.0; d += 0.1){
System.out.println(d);
}
Ergebnis:
0.0
0.1
0.2
0.30000000000000004
0.4
0.5
0.6
0.7
0.7999999999999999
0.8999999999999999
0.9999999999999999
Auch die Werte dieser Klassen sind Immutables
Auto-Boxing und Un-Boxing sind hier nicht verfügbar