1. Tablica — to kontener elementów
Prawdopodobnie wiesz, że komputery potrafią przetwarzać ogromne ilości informacji. Instrukcje warunkowe (if-else) i pętle (for, while) oczywiście w tym pomagają. Jednak daleko na nich nie zajedziemy, bo przetwarzane dane trzeba jakoś przechowywać.
W takich sytuacjach w Javie, podobnie jak w niemal wszystkich językach programowania, istnieje świetna konstrukcja: tablice (Array). Bywają też nazywane tabelami.
Tablica — to specjalny obiekt, w którym można przechowywać nie jedną wartość, lecz kilka.

Jeśli wcześniej porównywaliśmy zmienną do pudełka (w którym można przechowywać jakąś wartość), to tablica to raczej pudełko podzielone w środku na przegródki. Każda przegródka w „pudełku‑tablicy” ma swój numer. Numeracja, rzecz jasna, od zera...
Albo inna analogia. Porównajmy zwykły dom jednorodzinny i wielopiętrowy blok. Dom jednorodzinny zajmuje jedna rodzina, a blok jest podzielony na mieszkania. Aby napisać list do rodziny mieszkającej w domu, trzeba podać jego unikalny adres. A żeby napisać do rodziny mieszkającej w mieszkaniu, trzeba podać unikalny adres domu oraz numer mieszkania.
A więc zmienna‑tablica to „zmienna‑blok”. Można w niej przechowywać nie jedną wartość, lecz kilka. Taka zmienna ma kilka „mieszkań” (komórek), do każdej z których można się odwołać po jej numerze (indexie).
W tym celu po nazwie zmiennej w nawiasach kwadratowych należy podać index komórki, do której się odwołujemy. To dość proste:
array[index] = value;
Gdzie array — to nazwa zmiennej‑tablicy, index — numer komórki w tablicy, a value — wartość, którą chcemy umieścić we wskazanej komórce.
Najpierw jednak zobaczmy, jak tworzyć tablice.
2. Tworzenie tablicy elementów w Javie

Załóżmy, że Twoja aplikacja musi gdzieś przechować 100 liczb całkowitych. Najprawdopodobniej nada się do tego tablica. Jak ją utworzyć?
Gdybyśmy chcieli przechowywać jedną liczbę całkowitą, wystarczyłby typ int, a jeśli chcemy przechowywać 100 liczb całkowitych, najpewniej potrzebujemy tablicy typu int. Oto jak będzie wyglądał kod jej utworzenia:
int[] array = new int[100];
Przyjrzyjmy się, co tu zostało zapisane.
Jak zapewne się domyślasz, po lewej stronie znaku równości mamy deklarację zmiennej o nazwie array i typie int[]. Po typie int następują nawiasy kwadratowe, które sugerują, że w „pudełkach” tego typu można przechowywać nie jedną, lecz kilka wartości.
Po prawej stronie znaku równości widzimy „tworzenie obiektu” (słowo new) o 100 elementach (komórkach) typu int. Też niezbyt skomplikowane.
Gdybyśmy chcieli na przykład utworzyć tablicę na 20 komórek do przechowywania liczb zmiennoprzecinkowych, kod jej utworzenia wyglądałby mniej więcej tak:
double[] vals = new double[20];
Liczbę komórek w tablicy nazywamy rozmiarem tablicy lub długością tablicy. A dzięki zdolności przechowywania wielu wartości tablice nazywamy też kontenerami.
Ważny fakt: rozmiaru kontenera tablicy nie można zmienić po utworzeniu.
Można utworzyć nową, ale długości już utworzonego kontenera nie da się zmienić.
3. Praca z komórkami tablicy
Świetnie, potrafimy już tworzyć tablice, ale jak poprawnie z nich korzystać?
W zasadzie prawie tak samo jak ze zwykłymi zmiennymi, tylko po nazwie zmiennej‑tablicy obowiązkowo trzeba podawać numer komórki, z którą pracujemy.
Numeracja komórek tablicy zawsze zaczyna się od zera. Jeśli mamy tablicę na 10 elementów, to numery (indexy) jej komórek to 0..9, a jeśli tablicę na 200 elementów, to 0..199. I tak dalej, analogicznie.
Przykłady:
int[] a = new int[10]; // Tworzymy tablicę z 10 elementami typu int.
a[2] = 4; // Do komórki o indexie 2 zapisujemy wartość 4.
a[7] = 9; // Do komórki o indexie 7 zapisujemy wartość 9.
a[9] = a[2] + a[5]; // Do komórki o indexie 9 zapisujemy sumę wartości przechowywanych w komórkach 2
// (jest tam 4) i 5 (jest tam 0).
Oto co będzie przechowywane w pamięci po wykonaniu tego kodu:

Kolumna po lewej stronie tablicy (na szaro) — to numery (indexy) komórek. W komórkach przechowywane są wpisane wartości: 4, 9 i 4. Zaraz po utworzeniu komórki tablicy są wypełnione zerami.
Ważne. Wszystkie komórki tablicy mają ten sam typ danych. Jeśli utworzymy tablicę napisów String, w jej komórkach można przechowywać tylko napisy. Typ danych tablicy określa się w momencie jej tworzenia. Ani typu danych, ani długości tablicy później nie można zmienić.
4. Tablice w pamięci
Grafiki w poprzednich przykładach są nieco niedokładne.
Przy tworzeniu tablic (tak jak i przy tworzeniu napisów) w pamięci wydzielane są dwa bloki: jeden do przechowywania samej tablicy (kontenera), a drugi — dla zmiennej, która przechowuje jej adres. Sytuację doprecyzowano na ilustracji poniżej:

Kolorem zielonym pokazano tablicę na 10 elementów typu int oraz zmienną typu int[], która przechowuje adres (referencję) tablicy typu int w pamięci.
Dla porównania kolorem niebieskim zaznaczono zwykłą zmienną typu int, która przechowuje wartość 199.
Przypomina to nieco przechowywanie napisów w pamięci, prawda?
Dokładnie, napisy. I tak jak przy pracy z napisami, „zmienne typu tablica” można sobie przypisywać:
int[] a = new int[10]; // Tworzymy tablicę na 10 elementów typu int.
a[2] = 4; // Do komórki o indexie 2 zapisujemy wartość 4.
a[7] = 9; // Do komórki o indexie 7 zapisujemy wartość 9.
int[] b = a; // Do zmiennej b zapisujemy adres znajdujący się w zmiennej a.
// Teraz a i b wskazują na ten sam obiekt‑tablicę w pamięci.
a[9] = b[2] + a[7]; // Do komórki o indexie 9 obiektu‑tablicy zapisujemy sumę wartości,
// które przechowywane są w komórkach 2 (jest 4) i 7 (jest 9).
Przy tym obiekt‑tablica pozostanie tam, gdzie był, a zmienne a i b będą przechowywać te same adresy (referencje) do tego samego obiektu. Spójrz na grafikę:

5. Praca z tablicą bardziej szczegółowo
Tablicę można utworzyć z absolutnie każdego typu. Wystarczy po nazwie typu dopisać nawiasy kwadratowe. Ogólna postać tworzenia tablicy wygląda tak:
type[] name = new type[count];
Gdzie type — to typ elementów (komórek) tablicy, które będziemy przechowywać w tablicy. Imya — to nazwa zmiennej, za pomocą której będziemy się do tablicy odwoływać, a count — to liczba komórek w tablicy.
W powyższym przykładzie pokazano kanoniczną formę: utworzenie zmiennej‑tablicy i utworzenie obiektu‑tablicy. W rzeczywistości są to dwie niezależne konstrukcje. Można utworzyć zmienną‑tablicę i obiekt‑tablicę oddzielnie:
type[] name;
name = new type[count];
I jeszcze jedna istotna kwestia
Zarówno jako index tablicy, jak i jako liczba elementów tablicy mogą występować zmienne, a nawet całe wyrażenia.
Przykłady:
int n = 100;
int[] a = new int[n]; // Utworzenie tablicy z n elementów
int n = 100;
int[] a = new int[n * 2 + 3]; // Utworzenie tablicy na 203 elementy
int n = 100;
int[] a = new int[n];
a[n-1] = 2; // a[99] = 2;
a[n-2] = 3; // a[98] = 3;
a[n/5] = a[n-1] + a[n-2] // a[20] = a[99] + a[98];
Wyjście poza granice tablicy
Uwaga: jeśli spróbujesz odwołać się do komórki tablicy o indexie, którego w tablicy nie ma (w naszym przypadku są to wszystkie liczby całkowite poza zakresem 0..99), program zakończy się awaryjnie z błędem ArrayIndexOutOfBoundsException — index poza granicami tablicy.
6. Długość tablicy
Jak widzieliśmy w poprzednim przykładzie, można osobno utworzyć zmienną typu tablica, a potem gdzieś w kodzie przypisać jej wartość (referencję do obiektu‑tablicy). Można nawet zrobić tak:
int[] array; // Tworzymy zmienną‑tablicę typu int[]
if (a < 10) // Jeśli zmienna a jest mniejsza niż 10,
array = new int[10]; // to utwórz tablicę z 10 elementami.
else // W przeciwnym razie
array = new int[20]; // utwórz tablicę z 20 elementami
I jak dalej pracować z taką tablicą? Skąd wiedzieć, ile ma elementów?
W tym celu tablica ma specjalną właściwość (zmienną) — length. Długość tablicy można poznać za pomocą takiego wyrażenia:
array.length;
Gdzie array — to nazwa zmiennej‑tablicy, a length — to nazwa właściwości obiektu‑tablicy. Wartości w właściwości length nie można zmienić: samą właściwość length można przypisywać innym zmiennym, ale niczego nie można przypisać do niej (program po prostu się nie skompiluje).
Oto jak można kontynuować poprzedni przykład:
int[] array; // Tworzymy zmienną‑tablicę typu int[]
if (a < 10) // Jeśli zmienna a jest mniejsza niż 10,
array = new int[10]; // to utwórz tablicę z 10 elementami.
else // W przeciwnym razie
array = new int[20]; // utwórz tablicę z 20 elementami
for (int i = 0; i < array.length; i++) // Pętla po wszystkich elementach tablicy: od 0 do array.length — 1
{
System.out.println(array[i]);
}
7. Fakty o tablicach w Javie
Podsumujmy znane fakty o tablicach:
- Fakt 1. Tablica składa się z wielu komórek.
- Fakt 2. Dostęp do konkretnej komórki odbywa się przez podanie jej numeru.
- Fakt 3. Wszystkie komórki mają ten sam typ.
- Fakt 4. Wartość początkowa dla wszystkich komórek — to 0 i null (jeśli w komórce przechowywany jest adres), false (dla typu boolean).
- Fakt 5. String[] list — to tylko deklaracja zmiennej: sam kontener (obiekt‑tablica) nie został jeszcze utworzony. Aby można było z nim pracować, trzeba utworzyć tablicę (kontener) i umieścić ją w tej zmiennej, a potem z niej korzystać. Zob. przykład poniżej.
- Fakt 6. Gdy tworzymy obiekt‑tablicę (kontener), musimy podać, jaką ma długość — ile ma komórek. Robi się to poleceniem w postaci: new TypeName[n];
- Fakt 7. Długość tablicy można poznać poprzez właściwość .length.
- Fakt 8. Po utworzeniu tablicy nie można zmienić ani typu jej elementów, ani ich liczby.
String s; // s ma wartość null
String[] list; // list ma wartość null
list = new String[10]; // Zmienna list przechowuje referencję do obiektu – tablicy napisów z 10 elementami.
int n = list.length; // n jest równe 10
list = new String[0]; // Teraz list zawiera tablicę z 0 elementami.
// Tablica istnieje, ale nie może przechowywać elementów.
list = null;
System.out.println(list[1]); // Zostanie wygenerowany błąd — program zakończy się awaryjnie.
// list zawiera pustą referencję — null
list = new String[10];
System.out.println(list[10]); // Wystąpi błąd — wyjście poza granice tablicy.
// Jeśli list zawiera 10 elementów/komórek, dozwolone indexy to: 0 1 2 3 4 5 6 7 8 9 — łącznie 10 sztuk.
GO TO FULL VERSION