4 czerwca 2008

SCJP - Inicjalizacja tablic

W artykule "SCJP – Obiekty typu tablicowego" rozpocząłem temat tablic; dziś będzie kontynuacja. Będzie o składni, która pozwala na wygodną inicjalizację tablic.

Jak już sobie powiedzieliśmy tablice w języku Java są obiektami. Gdy potrzebujemy zmiennej typu prostego wystarczy, że zadeklarujemy taką zmienną i przypiszemy jej pewną wartość. Gdy potrzebujemy obiektu deklarujemy zmienną referencyjną, tworzymy ten obiekt i przypisujemy referencję do wspomnianej zmiennej. Jeśli tym obiektem jest tablica to dodatkowo chcielibyśmy przypisać pewne wartości elementom tej tablicy. Zerknijmy wpierw na poniższy kod, który deklaruje, tworzy i inicjalizuje tablicę "na piechotę".

public static void main(String[] args) {
int[] myTable = new int[4];

myTable[0] = 1;
myTable[1] = 2;
myTable[2] = 3;
myTable[3] = 4;
}

W pierwszej linii kodu deklarujemy zmienną referencyjną o nazwie ‘myTable’ zdolną do przechowywania referencji do obiektów typu ‘int[]’. Tworzymy także obiekt tablicy, który przechowuje cztery zmienne typu ‘int’. Referencję tego obiektu przypisujemy do zadeklarowanej zmiennej. Elementy tablic zawsze inicjowane są domyślnymi wartościami, tak więc wszystkie cztery elementy tablicy będą miały wartość ‘0’. Nie tego chcemy, więc w kolejnych liniach kodu przypisujemy inne wartości. Mamy co prawda to, czego chcieliśmy, ale powyższy sposób nie jest specjalnie wygodny – da się to samo zrobić dużo zgrabniej. Popatrzmy na kolejny przykład, który robi dokładnie to samo tyle, że z użyciem specjalnej składni inicjalizacji tablic.

public static void main(String[] args) {
int[] myTable = {1, 2, 3, 4};
}

Do zmiennej ‘myTable’ przypisujemy zatem wartość wyrażenia ‘{1, 2, 3, 4}’. Ponieważ jesteśmy w kontekście inicjalizacji zmiennej referencyjnej typu tablicowego kompilator wie, że chodzi o utworzenie tablicy. Po typie zmiennej referencyjnej rozpoznaje też, że chodzi o tablicę zmiennych typu ‘int’. Jedyne, czego jeszcze potrzebuje do utworzenia obiektu tablicy to rozmiar, ale to wiadomo na podstawie ilości wartości podanych w nawiasach klamrowych. Elementy tablicy inicjalizowane są właśnie tymi wartościami. Jak napisałem na początku tego akapitu kompilator wie, że chodzi o utworzenie tablicy ponieważ jesteśmy w kontekście inicjalizacji zmiennej referencyjnej typu tablicowego. W ogólności, nawiasy klamrowe obejmujące listę wartości nie są instrukcją konstrukcji tablicy. Z tego powodu język Java udostępnia jeszcze jedną konstrukcję, której znaczenie nie jest już zależne od kontekstu. Przykład poniżej.

public class Test {
public static void main(String[] args) {
printArray(new int[] {1, 2, 3, 4});
}

public static void printArray(int[] someArr) {
for(int x : someArr)
System.out.println(x);
}
}

Zerknijmy na wywołanie metody ‘printArray(…)’ w metodzie ‘main(…)’. Jak widać argumentem metody ‘printArray(…)’ jest tablica. Wywołując tą metodę nie przekazujemy jednak referencji do uprzednio utworzonej tablicy, przeciwnie, tablicę tworzymy w momencie wywołania metody (naturalnie tworzona jest ona tuż przed, ale ja mówię o zapisie). Zwróćmy uwagę, że tworząc tablicę w ten sposób nie podajemy explicite jej wymiaru – nie ma w nawiasach kwadratowych żadnej liczby. Rozmiar tablicy jest dedukowany na podstawie liczby elementów wymienionych między nawiasami klamrowymi. Próba określenia wprost wymiaru tablicy kończy się błędem kompilacji. Za pomocą analogicznych składni możemy także inicjalizować tablice wielowymiarowe. Zerknijmy na poniższy przykład.

public static void main(String[] args) {
byte[][] myTable = { { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 } };

for (byte[] table : myTable) {
for (byte x : table)
System.out.print(x + " ");

System.out.println();
}
}

W powyższym przykładzie tablica ‘myTable’ jest tablicą dwuwymiarową – mówiąc precyzyjniej tablicą tablic. Zawiera ona trzy tablice: { 1, 2 }, { 1, 2, 3 } oraz { 1, 2, 3, 4 }. Efektem uruchomienia programu będzie mozaika liczb pokazana poniżej.

1 2
1 2 3
1 2 3 4

Naturalnie, w analogiczny sposób możemy inicjalizować tablice obiektów. W szczególności, obiektami tymi mogą być tablice, choć oczywiście nie muszą. Poniżej przykład.

public class Test {
public static void main(String[] args) {
Number[][] myTable = { new Byte[] { 1, 2 }, new Integer[] { 1, 2, 3 }, {1, 2} };

for (Number[] table : myTable) {
for (Number x : table)
System.out.print(x + " ");

System.out.println();
}
}
}

A na koniec zagadka – zachęcam do zmierzania się z nią, jeśli chcesz mieć pewność, że w pełni rozumiesz temat tablic. Poniżej przedstawiono cztery deklaracje, druga jest błędna (nie kompiluje się) a pozostałe poprawne. Pytanie jest proste – dlaczego?

Object[] tableA = { new String[] { "some text" } };

Object[] tableB = { { "some text" } }; // błąd!

Object[][] tableC = { new String[] { "some text" } };

Object[][] tableD = { { "some text" } };

1 komentarz:

Anonimowy pisze...

Aha! Warto wiedzieć, że dla tablic typów prostych nie ma konwersji pomiedzy roznymi typami prostymi.

można

Object[] objs = new Number[]{};

ale nie można

long[] tab = new int[]{};

mimo, że może wydawać się, że int mieści się w long...

monsieur.lame