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
.
1 2 3 |
Object[] tab = {"1", 1}; System.out.println(Arrays.toString(tab)); System.out.println("Parametr 1: " + tab[0].getClass().getName() + ", Parametr 2: " + tab[1].getClass().getName()); |
na wyjściu pokazuje się następujący komunikat.
1 2 |
[1, 1] Parametr 1: java.lang.String, Parametr 2: java.lang.Integer |
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.
1 2 3 |
ArrayList<Integer> lista = new ArrayList<>(); ArrayList<Double> lista = new ArrayList<>(); ArrayList<Boolean> lista = new ArrayList<>(); |
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ć.
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.
Byte – byte
Short – short
Integer – int
Long – long
Float – float
Double – double
Boolean – boolean
Character – char
Przykładowa implementacja klasy opakowującej może wyglądać następująco.
1 2 3 4 5 6 7 8 9 10 |
class Integer { int value; //pola statyczne Integer(int val){ this.value = val } //metody statyczne konwersji } |
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.
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.
String
na int.
1 2 3 4 5 |
//konwersja String "1" na int int intFromString = Integer.parseInt("1"); //konwersja int na String String s = Integer.toString(1); |
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.
1 |
String s = "automatyczna konwersja " + 1; |
Podobnie można konwertować inne wartości całkowitoliczbowe np. String
na long, String
na short oraz String
na byte.
String
na float, double
1 2 3 4 5 |
//konwersja String na float float floatFromString = Float.parseFloat("1.0"); //konwersja float na String String s = Float.toString(1.0); |
1 2 3 4 5 |
//konwersja String na double double doubleFromString = Double.parseDouble("1.0"); //konwersja double na String String s = Double.toString(1.0); |
String
na bool
1 2 3 4 5 |
//konwersja String na bool bool boolFromString = Boolean.parseBoolean("True"); //konwersja double na String String s = Double.toString(true); |
Metoda parseBoolean()
konwertuje wartość „True” lub „true” (ignorując wielkość liter) na wartość logiczną true. W każdym innym przypadku zostanie przypisana wartość false.
String
na charPokażemy przykład jak zamienić obiekt String
na tablicę char oraz odwrotny przypadek.
1 2 3 4 5 6 7 8 9 |
//konwersja String na tablicę char char[] tabChar = "String to char".toCharArray(); //konwersja tablicy char String String s = String.valueOf(tabChar); //zamiana char na String char a = 'a'; String s = Character.toString(a); |
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.
1 2 |
int paczki = 10; paczki -= 1; |
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.
1 2 |
//obecnie niezalecane użycie konstruktora Integer val = new Integer(1); |
Ze względów wydajnościowych optymalnym rozwiązaniem jest użycie statycznej metody valueOf()
dostępnej w klasie Integer
.
1 |
Integer val = Integer.valueOf(1); |
Odpakowanie wartości z obiektu odbywa się za pomocą metody intValue()
.
1 2 |
//Zwrócenie typu prostego int primitiveVal = val.intValue(val); |
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()
.
1 2 3 |
Integer val = Integer.valueOf(1); ... val = Integer.valueOf(5); |
Analogicznie sytuacja wygląda gdy chcemy wykorzystać obiekt typu String
. Nie należy korzystać z konstruktora.
1 2 |
String number = "1" Integer val = Integer.valueOf(number); |
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.
1 2 3 4 5 |
ArrayList<Integer> lista = new ArrayList<>(); lista.add(1); //1 jest typem prostym int lista.add(2); ... int a = lista.get(0); //lista(0) |
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.
1 2 3 4 5 |
ArrayList<Integer> lista = new ArrayList<>(); lista.add(Integer.valueOf(1)); lista.add(Integer.valueOf(2)); ... int a = lista.get(0).intValue(); |
Jednakże tak napisany kod wydaje się być mniej czytelny.
1 2 3 |
Integer val = Integer.valueOf(1); Integer val2 = Integer.valueOf(3); System.out.print(++val + val2); |
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.
About the author