PO Kolekcje: Różnice pomiędzy wersjami
Nie podano opisu zmian |
Nie podano opisu zmian |
||
Linia 29: | Linia 29: | ||
[[grafika:PO_interfejsy_kolekcji.jpg]] | [[grafika:PO_interfejsy_kolekcji.jpg]] | ||
[[grafika:PO_interfejsy_kolekcji.png]] | <!-- [[grafika:PO_interfejsy_kolekcji.png]] --> | ||
[[grafika:PO_interfejsy_kolekcji.svg]] | <!-- [[grafika:PO_interfejsy_kolekcji.svg]] --> | ||
Wersja z 23:57, 21 sie 2006
Kolekcje
Wprowadzenie
Rzadko kiedy zdarzają się tak proste programy, którym do działania wystarcza kilka zmiennych zadeklarowanych w programie. Zwykle programy muszą operować na większej liczbie wartości. Wiemy już, że możemy w tym celu użyć tablic. Często jest to wystarczające rozwiązanie, ale ma ono pewne ograniczenia. Tablice mają stały rozmiar, a często przy pisaniu programów występują sytuacje, gdy liczba przechowywanych wartości zmienia się w trakcie działania programu. Co więcej bardzo często chcemy narzucić pewną strukturę przechowywanym wartościom (na przykład chcemy, by były posortowane, albo chcemy utrzymywać powiązanie między dwoma zestawami wartości). Ponieważ takie sytuacje zdarzają się bardzo często, praktycznie wszystkie współczesne języki programowania obiektowego dostarczają zestaw kolekcji - klas służących do przechowywania obiektów.
Ponieważ kolekcje mają być uniwersalne, to znaczy maja służyć do przechowywania obiektów różnych typów, w naturalny sposób do ich tworzenia wykorzystuje się omówione przez nas wcześniej typy uogólnione. Można nawet zaryzykować stwierdzenie, że kolekcje są głównym powodem, dla którego wprowadza się do języków programowania typy uogólnione.
Inną ciekawą dla nas cechą kolekcji jest ich organizacja. Wszystkie kolekcje służą do przechowywania obiektów. Skoro tak to są zestawem podobnych do siebie klas. A zatem naturalnie i wygodnie będzie przedstawić je w postaci hierarchii. Dzięki temu nauczenie się posługiwania się kolekcjami jest dużo prostsze. Nie musimy dla każdej kolekcji od nowa uczyć się jej interfejsu - języka jakim mamy się z nią porozumiewać. Jeśli raz nauczymy się ogólnego interfejsu kolekcji, to przy kolejnych członkach tej hierarchii będziemy musieli uczyć się jedynie specyficznych dla danej kolekcji pojęć i operacji. Co więcej, mając hierarchię kolekcji możemy tworzyć bardzo abstrakcyjne programy, które działają z (nieokreślona z góry) kolekcją zadaną jako parametr i w zależności od tego jaką kolekcję otrzymają inaczej się zachowują. Klasycznym przykładem jest tu problem obchodzenia grafu: jeśli program obchodzący graf dostanie jako parametr stos, to dokona obejścia grafu wgłąb, jeśli natomiast jako parametr otrzyma kolejkę, to obejdzie graf wszerz.
Kolejnym powodem dla którego tak dokładnie przyjrzymy się kolekcjom jest sposób dostępu do zawartych w nich danych. Oczywiście sam fakt przechowywania wartości nie wystarcza, ważne jest by można było wygodnie na nich operować. W tym celu w podejściu obiektowym stosuje się szereg standardowych technik, z których najczęściej spotykaną jest zastosowanie wzorca Iterator.
Nasze rozważania o kolekcjach zakończymy rozważeniem pewnych niebezpieczeństw związanych z ich stosowaniem. Przede wszystkim zastanowimy się co właściwie chcemy przechowywać w kolekcjach (oryginały czy ich kopie) oraz przyjrzymy się pewnym anomaliom pojawiającym się wtedy, gdy korzystając z niektórych kolekcji zapomnimy o przedefiniowaniu operacji ``equals lub hash.
Kolekcje w Javie
Zacznijmy od sprecyzowania pojęcia kolekcji. Przez kolekcję będziemy rozumieli obiekty służące do przechowywania (innych) obiektów i udostępniające mechanizmy pozwalające na wstawianie, przeglądanie i pobieranie składowanych w nich obiektów. Dodatkowo będziemy też oczekiwać, że kolekcja jest w stanie pomieścić w zasadzie dowolną (to znaczy ograniczoną tylko pojemnością pamięci komputera) liczbę obiektów, choć nie musi to oznaczać, że każda kolekcja ma mieć zmienny rozmiar (być może rozmiar będziemy musieli zadać od razu przy tworzeniu kolekcji). To dodatkowe żądanie oznacza, że np. obiektów klasy Para (z wykładu o typach uogólnionych), nie chcemy traktować jako kolekcji. Dla uproszczenia nazwą kolekcja będziemy również określać klasy obiektów będących kolekcjami i interfejsy definiujące właściwe dla kolekcji zachowania implementowane przez te obiekty.
Uwaga notacyjna: hierarchia interfejsów i klas kolekcji w Javie jest bardzo rozbudowana, przy czym ani dla interfejsów ani dla klas nie jest drzewem (w obu przypadkach jest lasem). W związku z tym, mimo tego że w pakiecie java.util występuje interfejs Collection nie wszystkie omawiane przez nas kolekcje go implementują czy dziedziczą. Tym nie mniej poręczniej będzie nam używać w dalszej części wykładu terminu kolekcja w szerszym znaczeniu (w odniesieniu do obiektów, klas i interfejsów służących do przechowywania grup obiektów), a nie tylko do podinterfejsów oraz klas i obiektów implementujących interfejs Collection).
Java dostarcza bardzo bogaty zestaw kolekcji, zawierający interfejsy, klasy abstrakcyjne i oczywiście klasy konkretne. Część z tych kolekcji służy specjalnym zastosowaniom (np. przy tworzeniu aplikacji webowych), część została stworzona z myślą o rozwiązaniu specyficznych problemów (np. związanych z synchronizowaniem dostępu do kolekcji przy programowaniu współbieżnym). W naszych rozważaniach nie będziemy ich brać pod uwagę i skupimy się jedynie na najbardziej ogólnych kolekcjach i ich zastosowaniu.
Kolekcje w Javie zostały umieszczone w pakiecie java.util, zatem na początku programów korzystających z kolekcji zazwyczaj umieszczamy deklarację umożliwiająca dostęp do całego pakietu:
import java.util.*;
Przegląd kolekcji
Przypisy
<references/>