Bardzo przydatną funkcją w Javie jest Arrays.asList(). Posiada jednak pewny kontrakt – zmiany w tablicy są widoczne w liście i na odwrót. Wynika to z faktu, że tworzona lista jest jedynie “widokiem” na tablicę – odwołuje się do tego samego miejsca na stercie. Obrazuje to poniższy przykład:
String[] tablica = new String[] {"1", "2", "3", "4", "5"};
List<String> list = Arrays.asList(tablica);
// zmiana elementu
list.set(0, "a");
for (String tab : tablica) {
System.out.print(tab + " ");
}
// dodanie nowego elementu
list.add("6");
for (String tab : tablica) {
System.out.print(tab + " ");
}
Wynikiem powyższych instrukcji jest:
a 2 3 4 5
UnsupportedOperationException
Jak widać zmiana elementu listy została odwzorowana również w tablicy, natomiast dodanie elementu do tablicy zakończyło się wyjątkiem. Jest to spowodowane faktem, że lista faktycznie odwołuje się do tablicy, która zaalokowana jest na stercie i jej powiększenie, bez utworzenia nowej tablicy jest niemożliwe.
Bezpieczeństwo typów dla kolekcji i tablic w Javie.
public class A {
public String getName() { return "A"; }
public static void main(String[] args) {
Set<B> bSet = new LinkedHashSet<B>();
Set<A> aSet = bSet; // THIS WILL NOT COMPILE
aSet.add(new C());
B[] bTable = new B[2];
A[] aTable = bTable;
aTable[0] = new B();
aTable[1] = new C(); //ArrayStoreException
}
}
public class B extends A {
@Override
public String getName() { return "B"; }
}
public class C extends A {
@Override
public String getName() { return "C"; }
}
Załóżmy, że istnieje możliwość przypisania obiektu LinkedHashSet<B> do zmiennej referencyjnej Set<A>. Na nowej referencji można wywołać metodę aSet.add(new C()), czego skutkiem tego jest dodanie obiektu C (podtypu klasy A) do trzymanego na stercie obiektu LinkedHashSet<B>, co jest błędne. Należy jednocześnie pamiętać, że typy genetyczne są zapominane podczas kompilacji i w rzeczywistości w pamięci istnieje obiekt Map. W związku z powyższym przy próbie rzutowania obiektu LinkedHashSet<B> na Set<A> otrzymujemy błąd kompilacji.
Mając analogiczną sytuację dla tablic nie otrzymujemy żadnego powiadomienia o błędzie od kompilatora podczas rzutowania. Dopiero po uruchomieniu dostajemy wyjątek: ArrayStoreException. Jest on związany z próbą dodania do tablicy niezgodnego typu obiektu. Należy pamiętać, że w momencie tworzenia tablic zapamiętują one swój typ.
Z powyższego przykładu widać, że korzystanie z kolekcji jest bezpieczniejsze niż z tablic.