Zagadki Java zawierają różnego rodzaju niuanse języka i „podchwytliwe” fragmenty kodu. Każda następna zagadka będzie zawierała odpowiedź i wyjaśnienie do poprzedniej. Lista wszystkich zagadek.
Jeżeli znasz odpowiedź, podziel się nią w komentarzu!
Zagadka Java #4¶
Jaki, oraz dlaczego, będzie wynik uruchomienia poniższej klasy?
import java.util.Arrays; import java.util.List; public class TabToList { public static void main(String[] args) { Integer[] tab = { 1, 10, 100 }; List<Integer> list = Arrays.asList(tab); // zmień wartość pierwszego elementu listy list.set(0, 5000); System.out.println(tab[0]); System.out.println(list.get(0)); list.add(111); // wyświetl wartość ostatniego elementu listy System.out.println(list.get(list.size() - 1)); } }
Odpowiedź do poprzedniej zagadki #3¶
Poniżej znajdziesz odpowiedź do poprzedniej zagadki.
W wyniku uruchomienia klasy JustMain, na ekranie zobaczymy:
Wynika z tego, że jeżeli klasy w hierarchii dziedziczenia posiadają pole o takiej samej nazwie, to możemy odnieść się do tego pola w konkretnej klasie, rzutując this na obiekt tej klasy:
((Cat) this).favoriteFood ((Animal) this).favoriteFood
W pierwszym przypadku rzutujemy this na obiekt klasy bazowej (MyCat dziedziczy po Cat). W drugim przypadku, rzutujemy this na klasę bazową klasy Cat (Cat dziedziczy po Animal). Dzięki temu zapisowi, odniesiemy się, odpowiednio, do pola favoriteFood z klasy Cat, oraz z klasy Animal. Tworzenie pól o takich samych nazwach w klasach podrzędnych może nie mieć dużego sensu, ale warto znać tę właściwość dziedziczenia.
Ten sam mechanizm nie zadziała w przypadku wywoływania metod – każda z poniższych linii:
this.eat(); ((Cat) this).eat(); ((Animal) this).eat();
Spowoduje wywołanie metody eat z klasy MyCat, o czym świadczy pierwsza część wyniku działania klasy JustMain:
Dzieje się tak, ponieważ, w przypadku metod, mamy do czynienia z mechanizmem method overriding (nadpisywanie metod). To, która metoda zostanie wywołana, zależy od faktycznego typu obiektu, którym jest obiekt wskazywany przez this. Rzutowanie na jedną z klas w hierarchii dziedziczenia nie ma, w przypadku metod, efektu.
Więcej na ten temat możesz przeczytać w oficjalnej specyfikacji języka Java.
Przepraszam poprzedni komentarz zawiera błędy, które dopiero teraz zauważyłem,
na początku powinno być oczywiście List list = Arrays.asList(tab)
oraz fragment ... zmienia się również wartość elementu tab[index]. Należy dodać, że oba odwołania wskazują na ten sam element w pamięci.
Chcąc uzyskać zamierzony cel należałoby zmienić wyrażenie List list = Arrays.asList(tab) na List list = new ArrayList(Arrays.asList(tab));
W efekcie program wykona się bezbłędnie i otrzymamy zamierzony wynik:
1
5000
111
Poproszę o krytyczne uwagi i serdecznie pozdrawiam
Dokładnie tak 🙂 Warto dodać, że typ obiektu zwracanego przez
Arrays.asList
toArrayList
, ale nieArrayList
z pakietujava.util
, lecz prywatnej, zagnieżdżonej klasy zdefiniowanej w klasieArrays
. Opis rozwiązania jest już dostępny wraz z kolejną zagadką: https://kursjava.com/zagadki-java-zagadka-5List list = Arrays.asList(Integer[] tab) - jest statyczną metodą zwracającą referencję do listy elementów tablicy będącej jej argumentem. Lista ta ma stały rozmiar (fixed-size) zatem nie posiada zdefiniowanych metod add() oraz remove(). Do elementów tej listy można odwoływać się poprzez index tak jak do tablicy, używając metody list.set(index, value) oraz list.get(index) zwracającej wartość o podanym indeksie. Ponieważ zmienna list zawiera referencję do tablicy tab to zmiana wartości elementu listy list.set(index, value) zmienia również wartość elementu array[index].
Podsumowując przedstawiony powyżej fragment programu skompiluje się, w wyniku wykonania otrzymamy wyniki:
5000
5000
a następnie w linii zawierającej instrukcję list.add() zostanie wygenerowany wyjątek UnsupportedOperationException