Autoboxing to automatyczna konwersja dokonywana przez kompilator języka Java między typami pierwotnymi i odpowiadającymi im klasami opakowania obiektów. Na przykład konwersja int na Integer, double na Double i tak dalej. Jeśli konwersja przebiega w drugą stronę, nazywa się to rozpakowywaniem.
Dlaczego więc tego potrzebujemy i dlaczego używamy autoboxingu i unboxingu w Javie?
java
autoboxing
Theodoros Chatzigiannakis
źródło
źródło
Integer
miećparseInt
metodę.int
nie ma. :)List<Integer>
, ale nie możeszList<int>
.Odpowiedzi:
Aby w pełni zrozumieć główny powód takiego stanu rzeczy, potrzebny jest kontekst.
Prymitywy a klasy
Zmienne pierwotne w Javie zawierają wartości (liczbę całkowitą, liczbę binarną zmiennoprzecinkową podwójnej precyzji itp.). Ponieważ te wartości mogą mieć różne długości , zawierające je zmienne mogą również mieć różne długości (rozważ w
float
porównaniudouble
).Z drugiej strony zmienne klasowe zawierają odniesienia do instancji. Odnośniki są zwykle implementowane jako wskaźniki (lub coś bardzo podobnego do wskaźników) w wielu językach. Te rzeczy mają zwykle ten sam rozmiar, niezależnie od wielkości tych przypadkach, których dotyczą (
Object
,String
,Integer
, etc).Ta właściwość zmiennych klasowych sprawia, że zawarte w nich odwołania są wymienne (do pewnego stopnia). To pozwala nam robić to, co nazywamy substytucją : mówiąc ogólnie, używać instancji określonego typu jako instancji innego, pokrewnego typu ( na przykład użyj a
String
jakoObject
).Zmienne pierwotne nie są zamienne w ten sam sposób, ani między sobą, ani z
Object
. Najbardziej oczywistym powodem tego (ale nie jedynym) jest różnica w wielkości. To sprawia, że typy prymitywne są pod tym względem niewygodne, ale nadal potrzebujemy ich w języku (z powodów, które sprowadzają się głównie do wydajności).Typy ogólne i usuwanie typów
Typy ogólne to typy z co najmniej jednym parametrem typu (dokładna liczba nazywana jest liczbą ogólną ). Na przykład definicja typu ogólnego
List<T>
ma parametr typuT
, którym może byćObject
(tworzenie konkretnego typuList<Object>
),String
(List<String>
),Integer
(List<Integer>
) i tak dalej.Typy ogólne są o wiele bardziej skomplikowane niż nieogólne. Kiedy zostały wprowadzone do Javy (po jej pierwszym wydaniu), aby uniknąć radykalnych zmian w JVM i być może zerwania kompatybilności ze starszymi plikami binarnymi, twórcy Javy zdecydowali się zaimplementować typy generyczne w jak najmniej inwazyjny sposób: wszystkie konkretne typy
List<T>
są w rzeczywistości skompilowane do (binarnego odpowiednika)List<Object>
(dla innych typów powiązanie może być czymś innym niżObject
, ale o co chodzi). W procesie tym następuje utrata ogólnych informacji o wartościach i parametrach typu , dlatego nazywamy to wymazywaniem typu .Łącząc te dwie rzeczy razem
Teraz problem jest kombinacja powyższych realia: jeśli
List<T>
staje sięList<Object>
we wszystkich przypadkach, po czymT
zawsze musi być typu, które mogą być bezpośrednio przypisaneObject
. Nie można pozwolić na nic innego. Ponieważ, jak już powiedzieliśmy,int
,float
idouble
nie są wymienne zObject
, tam nie może byćList<int>
,List<float>
lubList<double>
(chyba znacznie bardziej skomplikowane wdrożenie generycznych istniał w JVM).Ale Java oferty rodzaje podoba
Integer
,Float
aDouble
który zawijać tych prymitywów w instancji klasy, dzięki czemu skutecznie jako substytucyjneObject
, a tym samym pozwalając typy generyczne pośrednio pracy z prymitywów , jak również (bo może miećList<Integer>
,List<Float>
,List<Double>
i tak dalej).Proces tworzenia
Integer
ze związkuint
, AFloat
od Afloat
i tak dalej, nazywany jest boks . Odwrotność nazywa się unboxing . Ponieważ konieczność zaznaczania prymitywów za każdym razem, gdy chcesz ich używać,Object
jest niewygodna, są przypadki, w których język robi to automatycznie - nazywa się to autoboxingiem .źródło
Object
instancji. Jednym z zastosowań tego są typy generyczne poprzez usuwanie typów.Automatyczny boks jest używany do konwersji prymitywne typy danych do swoich obiektów klasy otoki. Klasa Wrapper zapewnia szeroki zakres funkcji do wykonania na typach pierwotnych. Najczęstszym przykładem jest:
int a = 56; Integer i = a; // Auto Boxing
To jest potrzebne ponieważ programiści mogą łatwo pisać kod, a JVM zajmie się Boxing i Unboxing.
Automatyczny boks przydaje się również podczas pracy z typami java.util.Collection. Kiedy chcemy stworzyć Kolekcję typów pierwotnych, nie możemy bezpośrednio stworzyć Kolekcji typu prymitywnego, możemy stworzyć Kolekcję tylko obiektów. Na przykład :
ArrayList<int> al = new ArrayList<int>(); // not supported ArrayList<Integer> al = new ArrayList<Integer>(); // supported al.add(45); //auto Boxing
Klasy opakowujące
Każdy z 8 typów pierwotnych Javy (byte, short, int, float, char, double, boolean, long) ma oddzielną skojarzoną z nimi klasę Wrapper. Te klasy Wrapper mają predefiniowane metody przeprowadzania przydatnych operacji na pierwotnych typach danych.
Korzystanie z klas opakowujących
String s = "45"; int a = Integer.parseInt(s); // sets the value of a to 45.
Istnieje wiele przydatnych funkcji, które zapewniają klasy Wrapper. Sprawdź dokumentację java tutaj
Unboxing jest przeciwieństwem Auto Boxing, w którym konwertujemy obiekt klasy opakowania z powrotem do jego pierwotnego typu. Jest to wykonywane automatycznie przez JVM, dzięki czemu możemy użyć klas opakowujących dla pewnych operacji, a następnie przekonwertować je z powrotem na typy pierwotne, ponieważ prymitywy powodują szybsze przetwarzanie. Na przykład :
Integer s = 45; int a = s; auto UnBoxing;
W przypadku kolekcji, które działają z obiektami, stosuje się tylko automatyczne rozpakowywanie. Oto jak :
ArrayList<Integer> al = new ArrayList<Integer>(); al.add(45); int a = al.get(0); // returns the object of Integer . Automatically Unboxed .
źródło
Typy pierwotne (niebędące przedmiotami) mają uzasadnienie w wydajności.
Typy pierwotne
int, boolean, double
to bezpośrednie dane, podczas gdyObject
s to odniesienia. Stąd pola (lub zmienne)int i; double x; Object s;
potrzebowałaby pamięci lokalnej 4 + 8 + 8? gdzie dla obiektu przechowywane jest tylko odniesienie (adres) do pamięci.
Używając opakowań Object
Integer, Double
i innych, można by wprowadzić pośrednie, odniesienie do jakiejś instancji Integer / Double w pamięci sterty.Dlaczego boks jest potrzebny?
To kwestia względnego zakresu. W przyszłej Javie planowane jest posiadanie
ArrayList<int>
, znoszącej prymitywne typy.Odpowiedź: Na razie ArrayList działa tylko dla Object, rezerwując miejsce na odniesienie do obiektu i podobnie zarządzając czyszczeniem pamięci. Stąd typy ogólne są elementami potomnymi Object. Więc jeśli ktoś chciał mieć ArrayList wartości zmiennoprzecinkowych, należało zawinąć double w obiekt Double.
Tutaj Java różni się od tradycyjnego C ++ swoimi szablonami: klasami C ++
vector<string>, vector<int>
utworzyłyby dwa produkty kompilacji. Projekt Java zakładał posiadanie jednego ArrayList.class, nie wymagając dla każdego typu parametru nowego skompilowanego produktu.Zatem bez pakowania w Object należałoby skompilować klasy dla każdego wystąpienia typu parametru. In concreto: każda kolekcja lub klasa kontenera wymagałaby wersji dla Object, int, double, boolean. Wersja dla Object obsługiwałaby wszystkie klasy potomne.
W rzeczywistości potrzeba takiej dywersyfikacji istniała już w Javie SE dla IntBuffer, CharBuffer, DoubleBuffer, ... które działają na int, char, double. Zostało to rozwiązane w hackerski sposób, generując te źródła ze wspólnego.
źródło
Począwszy od JDK 5, java dodał dwie ważne funkcje: autoboxing i autounboxing. AutoBoxing to proces, w którym typ pierwotny jest automatycznie hermetyzowany w równoważnym opakowaniu, gdy taki obiekt jest potrzebny. Nie musisz jawnie konstruować obiektu. Automatyczne rozpakowywanie to proces, w którym wartość hermetyzowanego obiektu jest automatycznie wyodrębniana z opakowania typu, gdy jest wymagana. Nie musisz wywoływać metody takiej jak intValue () lub doubleValue () .
Dodanie autoboxingu i auto-unboxingu znacznie upraszcza algorytmy pisania , eliminując przynętę ręcznego pakowania i rozpakowywania wartości. Pomocne jest również unikanie błędów . Jest to również bardzo ważne dla typów generycznych , które działają tylko na obiektach. Wreszcie, autoboxing ułatwia pracę z Collection Framework .
źródło
dlaczego mamy (nie) boks?
aby pisanie kodu, w którym mieszamy prymitywy i ich alternatywy obiektowe (OO), było wygodniejsze / mniej rozwlekłe.
dlaczego mamy prymitywy i ich OO alternatywy?
typy pierwotne nie są klasami (w przeciwieństwie do C #), dlatego nie są podklasami
Object
i nie można ich przesłonić.mamy prymitywy, takie jak
int
ze względu na wydajność, iObject
alternatywy, takie jakInteger
korzyści z programowania obiektowego, a także jako drobna kwestia, aby mieć dobrą lokalizację dla stałych narzędzi i metod (Integer.MAX_VALUE iInteger.toString(int)
).Korzyści OO są najłatwiej widoczne w Generics (
List<Integer>
), ale nie ograniczają się do tego, na przykład:Number getMeSome(boolean wantInt) { if (wantInt) { return Integer.MAX_VALUE; } else { return Long.MAX_VALUE; } }
źródło
Niektóre struktury danych mogą akceptować tylko obiekty, bez typów pierwotnych.
Przykład: klucz w HashMap.
Zobacz to pytanie po więcej: HashMap i int jako klucz
Istnieją inne dobre powody, takie jak pole „int” w bazie danych, które również może mieć wartość NULL. Int w Javie nie może mieć wartości null; odwołanie typu Integer can. Autoboxing i unboxing umożliwiają uniknięcie pisania zbędnego kodu podczas konwersji w obie strony.
źródło
Ponieważ są to różne typy i dla wygody. Wydajność jest prawdopodobnie przyczyną posiadania typów pierwotnych.
źródło
ArrayList nie obsługuje typów pierwotnych, obsługuje tylko klasy. ale musimy użyć typów pierwotnych, np. int, double itp.
ArrayList<String> strArrayList = new ArrayList<String>(); // is accepted. ArrayList<int> intArrayList = new ArrayList<int>(); // not accepted.
Klasa Integer opakowuje w obiekt wartość typu pierwotnego int, więc poniższy kod jest akceptowany.
ArrayList<Integer> intArrayList = new ArrayList<Integer>(); // is accepted.
możemy dodać wartość metodą add (value). Aby dodać wartość typu String, powiedz „Hello” w kodzie strArrayList is just
strArrayList.add("Hello");
i dodaj wartość int, powiedz 54 możemy napisać
intArrayList.add(54);
ale kiedy piszemy intArrayList.add (54); kompilator konwertuje do następującego wiersza
intArrayList.add(Integer.valueOf(54));
Ponieważ intArrayList.add (54) jest łatwy i bardziej akceptowalny ze strony użytkownika, kompilator wykonuje trudną pracę, którą jest ``
intArrayList.add(Integer.valueOf(54));
autoBoxing ''.Podobnie, aby pobrać wartość, po prostu wpisujemy intArrayList.get (0) i kompilator konwertuje na
<code>intArrayList.get(0).intValue();
który jest autoUnboxing.źródło
Autoboxing: Konwersja wartości pierwotnej na obiekt odpowiedniej klasy opakowania.
Rozpakowywanie: Konwersja obiektu typu opakowania na jego odpowiednią wartość pierwotną
// Java program to illustrate the concept // of Autoboxing and Unboxing import java.io.*; class GFG { public static void main (String[] args) { // creating an Integer Object // with value 10. Integer i = new Integer(10); // unboxing the Object int i1 = i; System.out.println("Value of i: " + i); System.out.println("Value of i1: " + i1); //Autoboxing of char Character gfg = 'a'; // Auto-unboxing of Character char ch = gfg; System.out.println("Value of ch: " + ch); System.out.println("Value of gfg: " + gfg); } }
źródło