Cześć! W poprzednich wykładach szczegółowo badaliśmy taką strukturę danych jak tablica i przyglądaliśmy się typowym przykładom pracy z nimi. Ale ta struktura danych ma wiele wad. Odpowiedzią na nie w Javie było pojawienie się ArrayList. Mówiąc najprościej, ArrayList w Javie to „ulepszona” tablica z wieloma nowymi funkcjami.
Czym różni się Java Arraylist od zwykłych tablic?
Generalnie tablice są dość wygodne i jak już zauważyłeś można z nimi zrobić mnóstwo rzeczy :) Tablice mają jednak też sporo wad.- Ograniczony rozmiar. Już na etapie tworzenia tablicy musisz wiedzieć, ile komórek powinna ona zawierać. Jeśli nie docenisz wymaganej ilości, nie będzie wystarczającej ilości miejsca. Jeśli przecenisz, tablica pozostanie w połowie pusta i nie jest tak źle. W końcu okazuje się, że przeznaczysz na to również więcej pamięci niż to konieczne.
- Tablica nie ma metod dodawania elementów. Zawsze musisz jawnie określić indeks komórki, do której chcesz dodać element. Jeśli przypadkowo określisz już zajętą komórkę z żądaną wartością, zostanie ona nadpisana.
- Nie ma metod usunięcia elementu. Wartość można jedynie „wyzerować”.
public class Cat {
private String name;
public Cat(String name) {
this.name = name;
}
public static void main(String[] args) {
Cat[] cats = new Cat[3];
cats[0] = new Cat("Tomasz");
cats[1] = new Cat("Hipopotam");
cats[2] = new Cat(„Filip Markowicz”);
cats[1] = null;
System.out.println(Arrays.toString(cats));
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
}
Wniosek:
[Cat{name='Томас'}, null, Cat{name='ФLubпп Маркович'}]
Wszystkie te niedociągnięcia można wyeliminować za pomocą ArrayList. Tworzy się go bardzo prosto:
ArrayList<Cat> cats = new ArrayList<Cat>();
Teraz stworzyliśmy listę do przechowywania obiektów Cat
. Zwróć uwagę:nie określamy rozmiaru ArrayList, ponieważ jest ona automatycznie rozwijana. Jak to jest możliwe? Łatwo. Zdziwisz się, ale ArrayList opiera się na zwykłej tablicy :) Tak, wewnątrz niej znajduje się tablica, w której przechowywane są nasze elementy. Ale ArrayList ma specjalny mechanizm pracy z nim:
- Kiedy ta wewnętrzna tablica jest pełna, ArrayList tworzy w sobie nową tablicę. Jego rozmiar = (rozmiar starej tablicy * 1,5) +1.
- Wszystkie dane zostaną skopiowane ze starej tablicy do nowej
- Stara tablica jest usuwana przez moduł zbierający elementy bezużyteczne.
add()
.
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<Cat>();
cats.add(new Cat("Hipopotam"));
}
Nowy element zostanie dodany na końcu listy. Teraz nie ma już ryzyka przepełnienia, więc mechanizm ten jest w pełni bezpieczny. Nawiasem mówiąc, ArrayList może nie tylko wyszukiwać obiekt według indeksu, ale także odwrotnie - może znaleźć indeks obiektu w ArrayList poprzez odniesienie do obiektu! W tym celu implementuje metodę indexOf()
: Podajemy do niego link do żądanego obiektu, a indexOf()
on zwraca nam swój indeks:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Tomasz");
Cat behemoth = new Cat("Hipopotam");
Cat philipp = new Cat(„Filip Markowicz”);
Cat pushok = new Cat("Puch");
cats.add(thomas);
cats.add(behemoth);
cats.add(philipp);
cats.add(pushok);
int thomasIndex = cats.indexOf(thomas);
System.out.println(thomasIndex);
}
Wniosek:
0
Zgadza się, obiekt thomas
jest faktycznie przechowywany w komórce 0
. Tablice mają nie tylko wady, ale także niewątpliwe zalety. Jednym z nich jest wyszukiwanie elementu po indeksie. Ponieważ wskazujemy na indeks, czyli na konkretny adres w pamięci, takie przeszukiwanie tablicy jest bardzo szybkie. ArrayList w Javie też może to zrobić! Aby to zrobić, implementuje metodę get()
:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Tomasz");
Cat behemoth = new Cat("Hipopotam");
Cat philipp = new Cat(„Filip Markowicz”);
Cat pushok = new Cat("Puch");
cats.add(thomas);
cats.add(behemoth);
cats.add(philipp);
cats.add(pushok);
Cat secondCat = cats.get(1);
System.out.println(secondCat);
}
Wniosek:
Cat{name='Бегемот'}
Możesz także łatwo sprawdzić, czy ArrayList zawiera określony obiekt, czy nie. Odbywa się to za pomocą metody contains()
:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Tomasz");
Cat behemoth = new Cat("Hipopotam");
Cat philipp = new Cat(„Filip Markowicz”);
Cat pushok = new Cat("Puch");
cats.add(thomas);
cats.add(behemoth);
cats.add(philipp);
cats.add(pushok);
cats.remove(pushok);
System.out.println(cats.contains(pushok));
}
Metoda sprawdza, czy element znajduje się w wewnętrznej tablicy ArrayList i zwraca wynik w postaci boolean
- true
lub false
. Wniosek:
false
I kolejna ważna rzecz dotycząca wkładania. ArrayList umożliwia wstawienie danych nie tylko na końcu tablicy, ale także do dowolnej komórki według indeksu. Ma na to dwie metody:
add(int index, Cat element)
set(int index, Cat element)
set()
zastępuje starą wartość przechowywaną w komórce. Wstawienie przez add()
pierwsze powoduje przesunięcie wszystkich elementów począwszy od [index]
końca tablicy i dodanie potrzebnego obiektu do wynikowej pustej komórki. Oto przykład:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Tomasz");
Cat behemoth = new Cat("Hipopotam");
Cat philipp = new Cat(„Filip Markowicz”);
Cat pushok = new Cat("Puch");
cats.add(thomas);
cats.add(behemoth);
System.out.println(cats.toString());
cats.set(0, philipp);//Teraz mamy listę 2 kotów. Dodajemy 3. przez zestaw:
System.out.println(cats.toString());
}
Wniosek:
[[Cat{name='Томас'}, Cat{name='Бегемот'}]
[Cat{name='ФLubпп Маркович'}, Cat{name='Бегемот'}]
Mieliśmy listę 2 kotów, metodą set()
do komórki wstawiliśmy kolejnego 0
. W rezultacie stara wartość przechowywana w tej komórce została zastąpiona nową.
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Tomasz");
Cat behemoth = new Cat("Hipopotam");
Cat philipp = new Cat(„Filip Markowicz”);
Cat pushok = new Cat("Puch");
cats.add(thomas);
cats.add(behemoth);
System.out.println(cats.toString());
cats.add(0, philipp);//Teraz mamy listę 2 kotów. Dodaj trzeci przez add
System.out.println(cats.toString());
}
Ale to add()
działało inaczej. Przesunął wszystkie elementy w prawo i następnie wpisał nową wartość do komórki 0
. Wniosek:
[Cat{name='Томас'}, Cat{name='Бегемот'}]
[Cat{name='ФLubпп Маркович'}, Cat{name='Томас'}, Cat{name='Бегемот'}]
Aby całkowicie wyczyścić listę, użyj metody clear()
:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Tomasz");
Cat behemoth = new Cat("Hipopotam");
Cat philipp = new Cat(„Filip Markowicz”);
Cat pushok = new Cat("Puch");
cats.add(thomas);
cats.add(behemoth);
cats.add(philipp);
cats.add(pushok);
cats.clear();
System.out.println(cats.toString());
}
Wniosek:
[]
Cała zawartość została usunięta z listy. Przy okazji, zwróć uwagę: w przeciwieństwie do tablic, w ArrayList metoda toString() jest nadpisana i natychmiast wyświetla listę w formacie string. W przypadku tablic musieliśmy do tego użyć klasy Arrays. A skoro przypomnieliśmy sobie Arrays: w Javie można łatwo „przełączać się” pomiędzy tablicą a ArrayList, czyli konwertować jedną na drugą. Klasa Arrays ma do tego metodę Arrays.asList(). Za jego pomocą pobieramy zawartość tablicy w postaci listy i przekazujemy ją konstruktorowi naszej ArrayList:
public static void main(String[] args) {
Cat thomas = new Cat("Tomasz");
Cat behemoth = new Cat("Hipopotam");
Cat philipp = new Cat(„Filip Markowicz”);
Cat pushok = new Cat("Puch");
Cat[] catsArray = {thomas, behemoth, philipp, pushok};
ArrayList<Cat> catsList = new ArrayList<>(Arrays.asList(catsArray));
System.out.println(catsList);
}
Wniosek:
[Cat{name='Томас'}, Cat{name='Бегемот'}, Cat{name='ФLubпп Маркович'}, Cat{name='Пушок'}]
Możesz także zrobić odwrotnie - uzyskać tablicę z obiektu ArrayList. Aby to zrobić, użyj metody toArray():
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Tomasz");
Cat behemoth = new Cat("Hipopotam");
Cat philipp = new Cat(„Filip Markowicz”);
Cat pushok = new Cat("Puch");
cats.add(thomas);
cats.add(behemoth);
cats.add(philipp);
cats.add(pushok);
Cat[] catsArray = cats.toArray(new Cat[0]);
System.out.println(Arrays.toString(catsArray));
}
Uwaga: przekazaliśmy pustą tablicę do metody toArray(). To nie jest błąd. Wewnątrz klasy ArrayList metoda ta jest zaimplementowana w taki sposób, że przekazanie pustej tablicy zwiększa jej wydajność. Na razie zapamiętaj to na przyszłość (ale możesz też przenieść konkretny rozmiar, będzie działać). Mówiąc o rozmiarze. Aktualny rozmiar listy można sprawdzić metodą size()
:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("Tomasz");
Cat behemoth = new Cat("Hipopotam");
Cat philipp = new Cat(„Filip Markowicz”);
Cat pushok = new Cat("Puch");
cats.add(thomas);
cats.add(behemoth);
cats.add(philipp);
cats.add(pushok);
System.out.println(cats.size());
}
Należy tutaj zrozumieć, że w przeciwieństwie do length
właściwości array metoda ArrayList.size() zwraca dokładnie liczbę elementów, a nie początkową pojemność, ponieważ nie określamy jej podczas tworzenia ArrayList. Nawiasem mówiąc, ogólnie można to wskazać. ArrayList ma odpowiedni konstruktor. Ale jego zachowanie w zakresie dodawania nowych elementów nie ulegnie zmianie:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>(2);// utwórz ArrayList o początkowej pojemności 2
Cat thomas = new Cat("Tomasz");
Cat behemoth = new Cat("Hipopotam");
Cat philipp = new Cat(„Filip Markowicz”);
Cat pushok = new Cat("Puch");
cats.add(thomas);
cats.add(behemoth);
cats.add(philipp);
cats.add(pushok);
System.out.println(cats.size());
}
Wyjście konsoli:
4
Stworzyliśmy listę z 2 elementami, ale kiedy jej potrzebowaliśmy, łatwo ją rozbudowywano. Inna sprawa, że jeśli początkowo stworzyliśmy bardzo małą listę, to będzie ona musiała częściej przeprowadzać operację rozszerzania, a to pochłania pewną ilość zasobów. W tym wykładzie ledwo poruszyliśmy proces usuwania elementów z listy ArrayList. Oczywiście nie jest to spowodowane zapomnieniem. Temat ten został wydzielony na osobny wykład, z którym możecie zapoznać się dalej :)
GO TO FULL VERSION