Klasy osłonowe w Javie

Klasy osłonowe (ang. wrapper class) pojawiły się w szkoleniu już wcześniej. W ostatnim wpisie dotyczącym klasy Object okazało się, że gdy utworzymy uniwersalny kontener w postaci tablicy typu Object mimo wpisania wartości 1 (typ prosty int) program pokazał, że element jest obiektem klasy Integer.

na wyjściu pokazuje się następujący komunikat.

Temat klas opakowujących sięga jednak dalej – okazuje się, że przemknął dość dyskretnie w przypadku kolekcji, a dokładniej klas implementujących interfejsy List, Set, Queue i Map. W celu usystematyzowania wiedzy przypominamy, że wszystkie klasy implementujące powyższe interfejsy są generyczne, co w dużym uproszczeniu oznacza, że kolekcje mogą przechowywać elementy określonego typu.

W nawiasie ostrym znajduje się nazwa klasy. Jedną z nich jest Integer, która jest klasą osłonową. Nie jest to typ prosty int i nie należy ich mylić.

Klasa osłonowa

Zadaniem klasy osłonowej jest zamknięcie wartości typu prostego w obiekt. Każdy z nich posiada swój obiektowy odpowiednik. Poniżej znajduje się ich lista podzielona według typów.

Liczby całkowite

Byte – byte

Short – short

Integer – int

Long – long

Liczby zmiennoprzecinkowe

Float – float

Double – double

Wartości logiczne

Boolean – boolean

Zmienne znakowe

Character – char

Przykładowa implementacja klasy opakowującej może wyglądać następująco.

Jak widać w powyższym listingu oprócz zmiennej, która przechowuje wartość obiektu znajduje się kilka pól oraz metod statycznych. Przykładami pól są przydatne informacje takie jak największa lub najmniejsza wartość danego typu prostego.

Zamiana typów (parsowanie)

W Javie w porównaniu do C# nie istnieje klasa taka jak Convert, która zawiera szereg metod do zamiany typów. Zamiast tego rozwiązania każda klasa osłonowa zawiera metody statyczne, które pozwalają zamieniać String na inne typy.

Zamiana String na int.

Warto zwrócić uwagę, że jeśli użyjemy operatora + (w przypadku łańcucha oznacza on konkatenację), to wartość int zostanie automatycznie skonwertowana do string.

Podobnie można konwertować inne wartości całkowitoliczbowe np. String na long, String na short oraz String na byte.

Zamiana String na float, double

Zamiana String na bool

Metoda parseBoolean() konwertuje wartość „True” lub „true” (ignorując wielkość liter) na wartość logiczną true. W każdym innym przypadku zostanie przypisana wartość false.

Zamiana String na char

Pokażemy przykład jak zamienić obiekt String na tablicę char oraz odwrotny przypadek.

Typ prosty a klasa osłonowa

W zmiennej typu int (oraz każdej innej typu prostego) można przechowywać wartość (oraz modyfikować), natomiast z uwagi na to, że nie są klasami, to nie posiadają żadnych zdefiniowanych metod. Natomiast sama ich deklaracja oraz działania są proste.

Jeżeli zmienna pokazuje liczbę pączków, które pozostały na sprzedaż, to można ją w prosty sposób modyfikować przez działania arytmetyczne.

Takie swobody jednak nie ma w przypadku obiektów Integer (oraz innych klas osłonowych).  Dotychczas obiekty klasy Integer (podobnie jak innych klas osłonowych) można było tworzyć przy pomocy słowa kluczowego new.

Ze względów wydajnościowych optymalnym rozwiązaniem jest użycie statycznej metody valueOf() dostępnej w klasie Integer.

Odpakowanie wartości z obiektu odbywa się za pomocą metody intValue().

Opakowane wartości są stałe, co oznacza, że nie można ich zmieniać w taki sposób jak typy proste. Podobnie jak w innych obiektach należy użyć znanej już metody valueOf().

Analogicznie sytuacja wygląda gdy chcemy wykorzystać obiekt typu String. Nie należy korzystać z konstruktora.

Automatyczne opakowywanie (ang. autoboxing)

Wróćmy teraz do klasy ArrayList, która implementuje kolekcję przechowującą obiekty dowolnej klasy. Nie jest możliwe przechowywanie typów prostych, takich jak int. Spójrzmy na poniższy listing.

W linii 2 do listy przechowującej kolekcję typu Integer został dodany typ prosty int? Z kolei w ostatniej linii wydaje się, że została wykonana odwrotna operacja. W rzeczywistości nie ma tu żadnej magii gdyż kompilator wykonuje konwersje w tle (automatycznie pakuje i wypakowuje wartość z obiektu osłonowego). Powyższy kod mógłby zostać również napisany w ten sposób.

Jednakże tak napisany kod wydaje się być mniej czytelny.

Podobna sytuacja ma miejsce tutaj. Wartości val oraz val2 są najpierw wypakowywane, a następnie val jest powiększana operatorem preinkrementacji o 1. Potem obliczana jest suma dwóch wartości, a na sam koniec następuje niejawna konwersja typu int do String.

W następnej części przyjrzymy się klasom StringBuilder i StringBuffer.