Jaka jest różnica pomiędzy
1.List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia)); //copy
2.List<Integer> list2 = Arrays.asList(ia);
gdzie ia
jest tablicą liczb całkowitych.
Dowiedziałem się, że niektóre operacje są niedozwolone list2
. dlaczego tak jest jak jest przechowywany w pamięci (odniesienia / kopia)?
Kiedy tasuję listy, list1
nie wpływa na oryginalną tablicę, ale list2
tak. Ale nadal list2
jest nieco zagmatwany.
W jaki sposób ArrayList
przeniesienie do listy różni się od tworzenia nowegoArrayList
list1 differs from (1)
ArrayList<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));
java
list
collections
Dineshkumar
źródło
źródło
Lists.newArrayList(ia)
tworzy niezależną kopię, tak jak pierwsza opcja. Jest po prostu bardziej ogólny i lepszy do obejrzenia.Odpowiedzi:
Najpierw zobaczmy, co to robi:
Pobiera tablicę
ia
i tworzy opakowanie, które implementujeList<Integer>
, dzięki czemu oryginalna tablica jest dostępna jako lista. Nic nie jest kopiowane i tworzony jest tylko jeden obiekt otoki. Operacje na opakowaniu listy są propagowane do oryginalnej tablicy. Oznacza to, że jeśli przetasujesz opakowanie listy, oryginalna tablica również zostanie przetasowana, jeśli nadpiszesz element, zostanie on nadpisany w oryginalnej tablicy itp. Oczywiście niektóreList
operacje na opakowaniu nie są dozwolone, takie jak dodawanie lub usuwając elementy z listy, możesz tylko czytać lub nadpisywać elementy.Zauważ, że opakowanie listy nie rozszerza się
ArrayList
- jest to inny rodzaj obiektu.ArrayList
s mają swoją własną tablicę wewnętrzną, w której przechowują swoje elementy i mogą zmieniać rozmiar tablic wewnętrznych itp. Opakowanie nie ma własnej tablicy wewnętrznej, a jedynie propaguje operacje do podanej tablicy.Z drugiej strony, jeśli później utworzysz nową tablicę jako
następnie tworzysz nowy
ArrayList
, który jest pełną, niezależną kopią oryginału. Chociaż tutaj tworzysz opakowanie również za pomocąArrays.asList
, jest ono używane tylko podczas budowy nowegoArrayList
i jest później zbierane jako śmieci. Struktura tego nowegoArrayList
jest całkowicie niezależna od oryginalnej tablicy. Zawiera te same elementy (zarówno oryginalna tablica, jak i noweArrayList
odwołanie, te same liczby całkowite w pamięci), ale tworzy nową, wewnętrzną tablicę, która przechowuje odwołania. Więc kiedy tasujesz, dodajesz, usuwasz elementy itp., Oryginalna tablica pozostaje niezmieniona.źródło
List<Integer>
dla typów zmiennych (lub argumentów metod itp.). Dzięki temu Twój kod jest bardziej ogólny i możesz łatwo przełączyć się na innąList
implementację w razie potrzeby, bez konieczności przepisywania dużej ilości kodu.A to dlatego, że
ArrayList
wynikający zArrays.asList()
nie jest tego typujava.util.ArrayList
.Arrays.asList()
tworzyArrayList
rodzaj,java.util.Arrays$ArrayList
który się nie rozszerza,java.util.ArrayList
a jedynie rozszerzajava.util.AbstractList
źródło
W tym przypadku
list1
jest typuArrayList
.Tutaj lista jest zwracana jako
List
widok, co oznacza, że zawiera tylko metody dołączone do tego interfejsu. Dlatego niektóre metody nie są dozwolonelist2
.Tutaj tworzysz nowy
ArrayList
. Po prostu przekazujesz mu wartość w konstruktorze. To nie jest przykład castingu. W castingu może wyglądać bardziej tak:źródło
Jestem tu dość późno, w każdym razie czułem, że wyjaśnienie z odniesieniami do doktora byłoby lepsze dla kogoś szukającego odpowiedzi.
ArrayList ma kilka przeciążonych konstruktorów
public ArrayList () - // zwraca arraylist o domyślnej pojemności 10
public ArrayList (Kolekcja c)
public ArrayList (int initialCapacity)
Więc kiedy przekażemy zwrócony obiekt Arrays.asList, tj. List (AbstractList) do drugiego konstruktora powyżej, utworzy on nową tablicę dynamiczną (ta wielkość tablicy rośnie, gdy dodajemy więcej elementów niż jej pojemność, a także nowe elementy nie wpłyną na tablicę oryginalną ) płytkie kopiowanie oryginalnej tablicy ( płytka kopia oznacza, że kopiuje tylko referencje i nie tworzy nowego zestawu tych samych obiektów co w oryginalnej tablicy)
źródło
lub
Powyższa instrukcja dodaje opakowanie do tablicy wejściowej. Zatem metody takie jak add & remove nie będą miały zastosowania do obiektu referencyjnego listy „namesList”.
Jeśli spróbujesz dodać element do istniejącej tablicy / listy, otrzymasz „Wyjątek w wątku” główny „java.lang.UnsupportedOperationException”.
Powyższa operacja jest tylko do odczytu lub tylko do przeglądania.
Nie możemy wykonać operacji dodawania lub usuwania w obiekcie listy. Ale
lub
W powyższej instrukcji utworzyłeś konkretną instancję klasy ArrayList i przekazałeś listę jako parametr.
W tym przypadku metoda add & remove będzie działać poprawnie, ponieważ obie metody pochodzą z klasy ArrayList, więc tutaj nie otrzymamy żadnego UnSupportedOperationException.
Zmiany wprowadzone w obiekcie Arraylist (metoda dodająca lub usuwająca element z / z listy arraylist) nie zostaną odzwierciedlone w oryginalnym obiekcie java.util.List.
źródło
Przede wszystkim klasa Arrays jest klasą narzędziową, która zawiera nie. metod narzędziowych do działania na Arrays (dzięki klasie Arrays w przeciwnym razie musielibyśmy stworzyć własne metody do działania na obiektach Array)
asList (), metoda:
asList
metoda jest jedną z narzędziArray
klasy, jest metodą statyczną, dlatego możemy wywołać tę metodę po nazwie klasy (np.Arrays.asList(T...a)
)ArrayList
obiektu, po prostu zwraca odniesienie List do istniejącegoArray
obiektu (więc teraz po użyciuasList
metodyArray
zostaną utworzone dwa odniesienia do istniejącego obiektu)List
obiekcie, mogą NIE działać na tym obiekcie Array przy użyciuList
referencji, jak na przykładArray
rozmiar s ma stałą długość, stąd oczywiście nie możesz dodawać ani usuwać elementów zArray
obiektu za pomocą tegoList
odniesienia (jaklist.add(10)
lublist.remove(10);
w przeciwnym razie zgłosi UnsupportedOperationException)Array
obiektu s (tak jak operujesz na istniejącym obiekcie Array przy użyciu odwołania do listy)W pierwszym przypadku tworzysz nowy
Arraylist
obiekt (w drugim przypadku tworzone jest tylko odniesienie do istniejącego obiektu Array, ale nie nowyArrayList
obiekt), więc teraz są dwa różne obiekty, jeden jestArray
obiektem, a drugi jestArrayList
obiektem i nie ma między nimi połączenia (więc zmienia się w jednym obiekcie nie zostanie odbity / zmieniony w innym obiekcie (to jest w przypadku 2Array
iArraylist
są to dwa różne obiekty)przypadek 1:
przypadek 2:
źródło
Wiele osób już udzieliło odpowiedzi na szczegóły mechaniczne, ale warto zauważyć: to zły wybór projektowy, według Javy.
asList
Metoda Java jest udokumentowana jako „Zwraca listę o stałym rozmiarze ...”. Jeśli weźmiesz jego wynik i wywołasz (powiedzmy).add
metodę, wyrzuci onaUnsupportedOperationException
. To nieintuicyjne zachowanie! Jeśli metoda mówi, że zwraca aList
, standardowym oczekiwaniem jest to, że zwraca obiekt, który obsługuje metody interfejsuList
. Deweloper nie powinien zapamiętywać, które z wieluutil.List
metod tworzą plikiList
, które w rzeczywistości nie obsługują wszystkichList
metod.Gdyby nazwali tę metodę
asImmutableList
, miałoby to sens. Albo gdyby metoda po prostu zwróciła rzeczywistąList
(i skopiowała tablicę podstawową), miałoby to sens. Postanowili faworyzować zarówno wydajność w czasie wykonywania, jak i krótkie nazwy, kosztem naruszenia zarówno zasady najmniejszej niespodzianki, jak i dobrej praktyki OO unikaniaUnsupportedOperationException
s.(Również projektanci mogli zrobić
interface ImmutableList
, aby uniknąć mnóstwaUnsupportedOperationException
s.)źródło
Zauważ, że w Javie 8, „ia” powyżej musi być liczbą całkowitą [], a nie int []. Arrays.asList () tablicy int zwraca listę z jednym elementem. Podczas korzystania z fragmentu kodu OP kompilator wychwyci problem, ale niektóre metody (np. Collections.shuffle ()) po cichu nie będą działać zgodnie z oczekiwaniami.
źródło
źródło
Arrays.asList()
ta metoda zwraca własną implementację List, pobiera tablicę jako argument i buduje na niej metody i atrybuty, ponieważ nie kopiuje żadnych danych z tablicy, ale używając oryginalnej tablicy powoduje to zmianę w oryginalnej tablicy podczas modyfikacji lista zwrócona przez
Arrays.asList()
metodę.z drugiej strony.
ArrayList(Arrays.asList());
jest konstruktoremArrayList
klasy, która przyjmuje listę jako argument i zwraca wartośćArrayList
niezależną od listy, tj.Arrays.asList()
w tym przypadku przekazane jako argument. dlatego widzisz te wyniki;źródło
W linii 2
Arrays.asList(ia)
zwracaList
odwołanie do zdefiniowanego wewnątrz obiektu klasy wewnętrznejArrays
, który jest również wywoływany,ArrayList
ale jest prywatny i tylko rozszerzaAbstractList
. Oznacza to, że to, co zostało zwrócone z,Arrays.asList(ia)
jest obiektem klasy innym niż ten, z którego otrzymujesznew ArrayList<Integer>
.Nie możesz użyć niektórych operacji do linii 2, ponieważ wewnętrzna klasa prywatna wewnątrz
Arrays
nie zapewnia tych metod.Spójrz na ten link i zobacz, co możesz zrobić z prywatną klasą wewnętrzną: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ Arrays.java # Arrays.ArrayList
Linia 1 tworzy nowy
ArrayList
obiekt kopiując elementy z tego, co otrzymujesz z linii 2. Możesz więc robić, co chcesz, ponieważjava.util.ArrayList
zapewnia wszystkie te metody.źródło
Podsumowanie różnic -
gdy lista jest tworzona bez użycia nowego operatora Arrays.asList () metoda zwraca Wrapper, co oznacza
1. możesz wykonać operację dodawania / aktualizacji.
2. zmiany dokonane w oryginalnej tablicy zostaną również odzwierciedlone w Liście i odwrotnie.
źródło
W odpowiedzi na kilka komentarzy zadających pytania dotyczące zachowania Arrays.asList () od wersji Java 8:
źródło