I_R_W13_M11_Java Struktury danych w Java
Dynamiczna alokacja pamięci
Maszyna wirtualna Javy przy uruchomieniu programu rezerwuje miejsce w pamięci RAM, które jest przeznaczone dla różnych komponentów maszyny. Wyjaśnimy działanie jedynie dwóch głównych sektorów wirtualnej pamięci Java, czyli sterty i stosu wątków.
![Zawartość stosu i sterty wirtualnej maszyny Java tuż przed zakończeniem działania metody pobierzWiek() Zawartość stosu i sterty wirtualnej maszyny Java tuż przed zakończeniem działania metody pobierzWiek(). Poniżej przestawiony jest kod: 1 class Osoba { 2 String imie; 3 int wiek; 4 static void pobierzImie(Osoba osoba) { 5 int wiekOsoby= osoba.wiek; 6 pobierzWiek(osoba); 7 } 8 static void pobierzWiek(Osoba osoba) { 9 String imieOsoby= osoba.imie; 10 } 11 public static void main(String[] args) { 12 int wiek = 18; 13 Osoba znajomy = new Osoba(); 14 Znajomy.imie="Paweł"; 15 znajomy.wiek=wiek; 16 { 17 } Po prawej stronie znajduje się kwadrat podpisany jako Wirtualna maszyna Java. Wewnątrz niej znajdują się dwa zielone prostokąty. Pierwszy podpisany jako stos a drugi jako Sterta. Z bloków Stosu wychodzą strzałki łączące je z blokami z sterty. Bloki w stosie: Pobierz wiek() zawierający: osoba połączona z osoba z sterta, oraz wiekOsoby=18. pobierzImie() zawierający: osoba połączony z osoba z sterta, imieOsoby połączony z "Paweł" z sterty. main() zawierający: wiek=18, znajomy połączona z Osoba z sterty. Starta zawiera blok Osoba z imie oraz wiek=18. String pool gdzie znajduje się "Paweł".](https://static.zpe.gov.pl/portal/f/res-minimized/R1cCHunLmGpUg/1736250847/2eLKzbystJvR5X9wDRp31IWZA8yC55VF.png)
pobierzWiek()Stos w wirtualnej maszynie Java to sekcja pamięci, która zawiera metody, zmienne lokalne i zmienne referencyjne. Dostęp do zawartości stosu jest zawsze wykonywany w kolejności LIFO. Gdy wywoływana jest funkcja, na szczycie stosu rezerwowany jest blok zawierający zmienne lokalne i referencje. Kiedy funkcja zakończy działanie blok odpowiadający funkcji zostaje zdjęty ze stosu, a wszystkie zmienne niezbędne do działania funkcji zostają usunięte.
Sterta to pamięć zarezerwowana na potrzeby alokacji dynamicznej. W przeciwieństwie do stosu nie ma wzorca określającego kolejność przydziału i zwalniania bloków. Można przydzielić blok w dowolnym momencie i w dowolnym czasie go zwolnić. Sterta służy do przechowywania typów obiektowych.
Zmienne referencyjne przechowują informację, gdzie obiekt, do którego się odwołują, przechowywany jest na stercie.
Zmienne String stworzone poprzez podanie wartości w cudzysłowie będą przechowywane w specjalnym miejscu na stercie zwanym String Pool. Inaczej będzie jeśli stworzymy obiekt typu String z użyciem słowa kluczowego new. Wtedy tak stworzony łańcuch znaków zostanie umieszczony poza String Pool w pewnym miejscu sterty (podobnie jak zwykły obiekt).
Garbage collector jest komponentem wirtualnej maszyny Java, który odpowiada za czyszczenie sterty. Śledzi obiekty w stercie i sprawdza, ile referencji odwołuje się do każdego z nich. Jeśli komponent zauważy obiekt, do którego nie odwołuje się żadna referencja, zwalnia obiekt ze sterty.
Stos | Sterta |
|---|---|
zmienne utworzone na stosie, które wyjdą poza zakres, są automatycznie usuwane | obiekty, do których nie odwołuje się żadna referencja, są usuwane przez Garbage collector |
jest szybszy w alokacji w porównaniu ze stertą | jest wolniejsza w alokacji w porównaniu ze stosem |
przechowuje jedynie metody i zmienne lokalne metody | przechowuje instancje obiektów, do których odwołujemy się za pomocą referencji |
może wystąpić przepełnienie, gdy zbyt dużo elementów znajduje się na stosie | mogą wystąpić błędy alokacji, jeśli zażądano przydzielenia zbyt dużego rozmiaru pamięci |
jeśli stos jest przepełniony, Java zgłasza | jeśli sterta jest zapełniona, Java zgłasza błąd |
Tablice dynamiczne
W języku Java klasyczne tablice mają stałą wielkość. Oznacza to, że po tym jak nadamy im określony rozmiar, nie można ich rozszerzać ani zmniejszać. Aby zmienić rozmiar, trzeba utworzyć nową tablicę i skopiować dotychczasowe elementy. Operacja taka jest wysoce nieefektywna i uciążliwa.
Na szczęście istnieje już zdefiniowana kolekcja, która dostosowuje swój rozmiar, kiedy tylko zajdzie taka potrzeba. Kolekcja ta nazywa się ArrayList (znana także jako lista tablicowa) i jest jedną z klas Java Collection Framework. Listy tablicowe są również nazywane tablicami dynamicznymi, ponieważ ich rozmiar może się zmieniać w trakcie działania programu.
By skorzystać z tejże kolekcji, zaimportujemy zarówno klasę java.util.ArrayList, jak i interfejs java.util.List. Obiekt tej kolekcji deklarujemy następująco:
Lista tablicowa jest klasą generyczną z parametrem określonego typu, dlatego należy określić wewnątrz nawiasów ostrych typ przechowywanych wyrazów. Jedynym ograniczeniem jest to, że wyrazy muszą być obiektem. Dla typów prymitywnych należy wpisać ich obiektowy odpowiednik. Na przykład, jeśli lista tablicowa ma składać się z liczb całkowitych, musimy wpisać Integer tam, gdzie określamy typ przechowywanych elementów.
Sama lista tablicowa w tym momencie jest pusta, ale możemy modyfikować zawartość kolekcji niektórymi z metod opisanych w tabeli.
| Dodaje element na początek stosu; zwraca |
|---|---|
| Zwraca element na określonej pozycji podanej przez argument, lista tablicowa musi zawierać podaną pozycję. |
| Usuwa wszystkie wyrazy z listy tablicowej, w konsekwencji lista tablicowa staje się pusta. |
| Zwraca liczbę wszystkich wyrazów aktualnie znajdujących się w liście tablicowej. |
| Przypisuje wyrazowi o pewnym indeksie daną wartość, np. instrukcja: zmienia wartość elementu listy |
| Usuwa wyraz na określonej pozycji listy tablicowej. |
Funkcja | Zastosowanie |
|---|---|
| Dodaje element na początek stosu; zwraca |
| Zwraca element na określonej pozycji podanej przez argument, lista tablicowa musi zawierać podaną pozycję. |
| Usuwa wszystkie wyrazy z listy tablicowej, w konsekwencji lista tablicowa staje się pusta. |
| Zwraca liczbę wszystkich wyrazów aktualnie znajdujących się w liście tablicowej. |
| Przypisuje wyrazowi o pewnym indeksie daną wartość, np. instrukcja: zmienia wartość elementu listy |
| Usuwa wyraz na określonej pozycji listy tablicowej. |
Metodę remove najlepiej stosować tylko dla elementów znajdujących się na końcu kolekcji. Wtedy nie tracimy zbyt dużo na szybkości działania, ponieważ złożoność czasowa takiej operacji wynosi . W sytuacjach, które wymagają usuwania elementów niekoniecznie znajdujących się na końcu, stosujemy inną kolekcję, np. LinkedList.
Lista tablicowa jest stosowana w każdej sytuacji, gdy priorytetem jest szybki dostęp do elementów kolekcji, które usuwać będziemy tylko w ostateczności.
Na pewno spotkamy się z sytuacją, w której potrzeba będzie iterować po każdym elemencie listy tablicowej. Sposobów iteracji jest wiele, my skupimy się na dwóch najefektywniejszych - przy użyciu pętli for oraz jej rozszerzonej wersji.
Iteracja pętlą for
Zapoznajmy się z przykładem iterowania po każdym elemencie listy tablicowej, w którym wykorzystujemy pętlę for.
Wynik działania programu:
Iteracja rozszerzoną pętlą for
W tym przykładzie wykorzystujemy rozszerzoną pętlę for‑each. Rozszerzona pętla for‑each umożliwia prostsze i bardziej czytelne iterowanie po elementach kolekcji, takich jak tablice czy listy, bez konieczności korzystania z tradycyjnej pętli for z indeksami.
Pętla for‑each jest używana w następujący sposób:
W przypadku tego kodu int wyraz : listaTablicowa, typ elementu to int, ponieważ listaTablicowa przechowuje obiekty typu Integer.
Wewnątrz pętli for‑each każdy element wyraz z listy listaTablicowa jest dostępny w każdej iteracji, a kod w bloku pętli może operować na tym elemencie. W tym przypadku każdy element listy jest wyświetlany za pomocą System.out.print(wyraz + " "), co powoduje wyświetlenie elementów listy oddzielonych spacją w jednej linii.
Rozszerzona pętla for‑each jest użyteczna, gdy chcemy przeiterować po wszystkich elementach kolekcji bez konieczności śledzenia indeksów ani długości kolekcji. Jest to prosty i czytelny sposób przeglądania elementów w kolekcji, który pomaga uniknąć błędów związanych z indeksami oraz skraca kod.
Wynik działania programu: