W tym artykule przyjrzymy się funkcji w Javie zwanej
autoboxingiem/unboxingiem . Automatyczne pakowanie i rozpakowywanie to funkcje konwersji typów pierwotnych na typy obiektowe i odwrotnie.
Cały proces jest wykonywany automatycznie przez środowisko Java Runtime Environment (JRE). Ale należy zachować ostrożność podczas wdrażania tej funkcji, ponieważ... Może to mieć wpływ na wydajność programu.
Wstęp
int
W wersjach poniżej JDK 1.5 konwersja prymitywnych typów danych, takich jak ,
char
,
float
,
double
na ich klasy opakowania Integer, Character, Float, Double nie była łatwa . Począwszy od JDK 5, ta funkcjonalność, konwertująca typy pierwotne na równoważne obiekty, jest implementowana automatycznie. Ta właściwość jest znana jako
Autoboxing . Procesem odwrotnym jest odpowiednio
Unboxing , czyli rozpakowywanie. proces przekształcania obiektów w odpowiadające im typy pierwotne. Przykładowy kod do automatycznego pakowania i rozpakowywania znajduje się poniżej:
Autoboxing
Integer integer = 9;
Rozpakowywanie
int in = 0;
in = new Integer(9);
Kiedy stosuje się automatyczne pakowanie i rozpakowywanie? Autoboxing jest używany przez kompilator Java pod następującymi warunkami:
- Gdy wartość typu pierwotnego jest przekazywana do metody jako parametr metody, która oczekuje obiektu odpowiedniej klasy opakowania.
- Gdy wartość typu pierwotnego jest przypisana do zmiennej odpowiedniej klasy opakowania.
Rozważmy następujący przykład:
Listing 1: Prosty kod pokazujący autoboxing
public int sumEvenNumbers(List<Integer> intList ) {
int sum = 0;
for (Integer i: intList )
if ( i % 2 == 0 )
sum += i;
return sum;
}
Przed wersją jdk 1.5 powyższy kod powodowałby błąd kompilacji, ponieważ nie można było zastosować pozostałego operatora % i unary plus += do klasy opakowania. Ale w jdk 1.5 i nowszych wersjach ten kod kompiluje się bez błędów, konwertując liczbę całkowitą na
int
. Unboxing jest używany przez kompilator Java pod następującymi warunkami:
- Gdy obiekt jest przekazywany jako parametr do metody, która oczekuje odpowiedniego typu pierwotnego.
- Gdy obiekt jest przypisany do zmiennej odpowiedniego typu pierwotnego.
Rozważmy następujący przykład:
Listing 2: Prosty kod pokazujący rozpakowywanie
import java.util.ArrayList;
import java.util.List;
public class UnboxingCheck {
public static void main(String[] args) {
Integer in = new Integer(-8);
int absVal = absoluteValue(in);
System.out.println("absolute value of " + in + " = " + absVal);
List<Double> doubleList = new ArrayList<Double>();
doubleList.add(3.1416);
double phi = doubleList.get(0);
System.out.println("phi = " + phi);
}
public static int absoluteValue(int i) {
return (i < 0) ? -i : i;
}
}
Autoboxing i unboxing pozwala programiście napisać kod, który jest łatwy do odczytania i zrozumienia. W poniższej tabeli przedstawiono podstawowe typy danych i odpowiadające im obiekty opakowania.
Typy pierwotne |
Klasy powłoki |
wartość logiczna |
Wartość logiczna |
bajt |
Bajt |
zwęglać |
Postać |
platforma |
Platforma |
wew |
Liczba całkowita |
długi |
Długi |
krótki |
Krótki |
Tabela 1: Typy pierwotne i równoważne klasy opakowań z operatorami porównania W przypadku operatorów porównania można używać funkcji automatycznego pakowania i rozpakowywania. Poniższy fragment kodu ilustruje, jak to się dzieje:
Listing 3: Przykładowy kod pokazujący automatyczne pakowanie i rozpakowywanie za pomocą operatora porównania
public class BoxedComparator {
public static void main(String[] args) {
Integer in = new Integer(25);
if (in < 35)
System.out.println("Value of int = " + in);
}
}
Autopakowanie i rozpakowywanie przy przeciążaniu metody Autopakowanie i rozpakowywanie odbywa się przy przeciążaniu metody w oparciu o następujące zasady:
- Ekspansja „pokonuje” opakowanie w sytuacji, gdy istnieje wybór pomiędzy ekspandowaniem a pakowaniem; preferowane jest ekspandowanie.
Listing 4: Przykładowy kod pokazujący korzyści z przeciążenia
public class WideBoxed {
public class WideBoxed {
static void methodWide(int i) {
System.out.println("int");
}
static void methodWide( Integer i ) {
System.out.println("Integer");
}
public static void main(String[] args) {
short shVal = 25;
methodWide(shVal);
}
}
}
Dane wyjściowe programu - typ
int
- Rozszerzanie pokonuje zmienną liczbę argumentów. W sytuacji, gdy staje się wyborem między rozwinięciem a zmienną liczbą argumentów, preferowane jest rozwinięcie.
Listing 5: Przykładowy kod pokazujący korzyści z przeciążenia
public class WideVarArgs {
static void methodWideVar(int i1, int i2) {
System.out.println("int int");
}
static void methodWideVar(Integer... i) {
System.out.println("Integers");
}
public static void main( String[] args) {
short shVal1 = 25;
short shVal2 = 35;
methodWideVar( shVal1, shVal2);
}
}
- Pakowanie przewyższa zmienną liczbę argumentów. W sytuacji, gdy staje się wyborem pomiędzy pakowaniem a zmienną liczbą argumentów, preferowane jest pakowanie.
Listing 6: Przykładowy kod pokazujący korzyści z przeciążenia
public class BoxVarargs {
static void methodBoxVar(Integer in) {
System.out.println("Integer");
}
static void methodBoxVar(Integer... i) {
System.out.println("Integers");
}
public static void main(String[] args) {
int intVal1 = 25;
methodBoxVar(intVal1);
}
}
Korzystając z automatycznego pakowania, powinieneś pamiętać o następujących kwestiach: Jak wiemy, każda dobra funkcja ma wadę. Automatyczne pakowanie nie jest pod tym względem wyjątkiem. Kilka ważnych uwag, o których programista powinien pamiętać podczas korzystania z tej funkcji:
- Porównywanie obiektów za pomocą
==
operatora „” może być mylące, ponieważ można go zastosować do pierwotnych typów i obiektów. Gdy ten operator zostanie zastosowany do obiektów, w rzeczywistości porównuje odniesienia do obiektów, a nie do samych obiektów.
Listing 7: Przykładowy kod pokazujący porównanie.
public class Comparator {
public static void main(String[] args) {
Integer istInt = new Integer(1);
Integer secondInt = new Integer(1);
if (istInt == secondInt) {
System.out.println("both one are equal");
} else {
System.out.println("Both one are not equal");
}
}
}
- Mieszanie obiektów i typów pierwotnych za pomocą operatorów równości i relacyjnych. Jeśli porównamy typ pierwotny z obiektem, wówczas obiekt zostanie rozpakowany, co może wyrzucić,
NullPointerException
jeśli obiekt null
.
- Buforowanie obiektów. Metoda
valueOf()
tworzy kontener prymitywnych obiektów, które buforuje. Ponieważ wartości są buforowane w zakresie od -128 do 127 włącznie, te buforowane obiekty mogą zachowywać się inaczej.
- Obniżenie wydajności. Automatyczne pakowanie lub rozpakowywanie obniża wydajność aplikacji, ponieważ tworzy niechciany obiekt, który wymusza częstsze działanie modułu zbierającego elementy bezużyteczne.
Wady AutoBoxingu Chociaż AutoBoxing ma wiele zalet, ma następujące wady:
Listing 8: Przykładowy kod pokazujący problem z wydajnością.
public int sumEvenNumbers(List intList) {
int sum = 0;
for (Integer i : intList) {
if (i % 2 == 0) {
sum += i;
}
}
return sum;
}
W tej części kodu
sum +=i
zostanie on rozwinięty do
sum = sum + i
. Zaczynając od
+
operatora „”, JVM rozpoczyna rozpakowywanie, ponieważ
+
operatora „” nie można zastosować do obiektu typu Integer. Następnie wynik jest automatycznie pakowany z powrotem. Przed JDK 1.5 typy danych
int
i liczby całkowite były inne. W przypadku przeciążenia metod te dwa typy były stosowane bez problemów. Wraz z pojawieniem się automatycznego pakowania/rozpakowywania stało się to trudniejsze. Przykładem tego jest przeciążona metoda
remove()
w
ArrayList
. Klasa
ArrayList
ma dwie metody usuwania -
remove(index)
i
remove(object)
. W takim przypadku nie nastąpi przeciążenie metody i zostanie wywołana odpowiednia metoda z odpowiednimi parametrami.
Wniosek
Autoboxing to mechanizm niejawnego konwertowania prymitywnych typów danych na odpowiadające im klasy opakowania (obiekty). Kompilator używa metody
valueOf()
do konwersji typów pierwotnych na obiekty, a metod itp
IntValue()
.
doubleValue()
do uzyskania typów pierwotnych obiektu. Autoboxing konwertuje typ boolowski
boolean
na logiczny,
byte
na bajt,
char
na znak,
float
na zmiennoprzecinkowy,
int
na liczbę całkowitą,
long
na długi,
short
na krótki. Rozpakowanie następuje w odwrotnym kierunku.
Oryginalny artykuł
GO TO FULL VERSION