Podsumowanie okazało się dość kłopotliwe, dlatego podzieliłem je na dwie części. Część druga zawiera odpowiedzi na pytania dotyczące kankarencji i wielowątkowości. Pierwsza część zawiera resztę. Pisanie było dość trudne. Nadal niewiele rozumiem, więc jak zwykle komentarze, uwagi, uzupełnienia mile widziane)
1. Jak korzystać z interfejsu Comparable?
Interfejs
Comparable
deklaruje tylko jedną metodę
compareTo(Object obj)
, przeznaczoną do implementacji porządkowania obiektów klas. Jest wygodny w użyciu podczas sortowania uporządkowanych list lub tablic obiektów. Ta metoda porównuje wywoływany obiekt z
obj. W przeciwieństwie do metody
equals
, która zwraca
wartość true lub
false ,
compareTo
zwraca:
- 0, jeśli wartości są równe;
- Wartość ujemna, jeśli wywoływany jest mniejszy niż parametr;
- Dodatnia, jeśli wywoływany jest większy niż parametr.
Jest przede wszystkim przydatny do sortowania uporządkowanych list (
java.util.List
) i tablic obiektów. Jeśli lista/tablica zawiera elementy implementujące ten interfejs, można je automatycznie posortować według
java.util.Collections.sort(List)/Arrays.sort(Object[])
. Koncepcja porządku naturalnego jest kojarzona z interfejsem
Comparable
, ponieważ ustanawia naturalny porządek instancji dowolnej klasy, która implementuje ten interfejs. Inaczej mówiąc, rząd (x, y) odpowiada spełnieniu warunku
x.compareTo(y) <= 0
. Zasady implementacji
Comparable
, a raczej jej metody,
compareTo(Object)
są następujące (x i y są instancjami klasy, która implementuje
Comparable
):
x.compareTo(y)
zwraca -1 lub 1, jeśli x powinno znajdować się odpowiednio przed lub po y. Jeśli metoda zwróci 0, to rzędy (x, y) i (y, x) są równoważne.
- Jeśli
sign(a)
jest funkcją zwracającą -1,0,1 dla odpowiednio mniejszego od 0, równego 0 i większego od 0, to równość musi być spełniona sign(x.compareTo(y))==-sign(y.compareTo(x))
. Co jest logiczne: jeśli x występuje przed y, to y musi nastąpić po x i odwrotnie.
- Jeżeli
x.compareTo(y) > 0
i y.compareTo(z) > 0
, to x.compareTo(z) > 0
– relacja przechodniości nierówności.
- Jeżeli
x.compareTo(y) == 0
, to sign(x.compare(z)) == sign(y.compareTo(z))
dla dowolnego z.
- Wywołanie
x.compareTo(null)
musi zgłosić wyjątek NullPointerException
. Jest to rozbieżność z logiką implementacji equals
(przypomnę, x.equals(null)
zwraca false ).
- Jeśli typu y nie można porównać z x, wówczas wywołanie
x.compareTo(y)
musi zgłosić wyjątek ClassCastException
.
(x.compareTo(y) == 0) == x.equals(y)
, tj. wywołanie x.compareTo(y)
musi zwrócić 0 wtedy i tylko wtedy, gdy x.equals(y)
zwróci wartość true . Jest to zasada konsekwencji, którą należy wziąć pod uwagę.
Źródła:
2. Jak korzystać z interfejsu Komparatora?
Interfejs
Comparator
deklaruje dwie metody
compare(Object obj1, Object obj2)
i
equals(Object obj)
. Podczas korzystania z interfejsu
Comparator
logika porównywania pary obiektów nie jest ukryta wewnątrz klasy/obiektu, ale jest zaimplementowana w osobnej klasie. Metoda
compare(x,y)
jest dokładnie taka sama jak wywołanie
x.compareTo(y)
. Wszystkich reguł należy przestrzegać dokładnie w taki sam sposób, jak zasad implementacji metody
compareTo(Object)
interfejsu
Comparable
.
Comparator
można zastosować wszędzie tam, gdzie potrzebne jest sortowanie. W tym przypadku po pierwsze pojawia się niezbędna elastyczność - możliwość wdrożenia kilku reguł sortowania. Po drugie, sortowane obiekty mogą nie implementować metody
Comparable
. Jeśli to wdrożą,
Comparator
ma to pierwszeństwo. Interfejs
Comparator
definiuje także metodę
equals(Object)
, choć może to paradoksalnie. Ta metoda porównuje same instancje interfejsu
Comparator
i powinna zwracać wartość
true tylko wtedy, gdy porównywane obiekty zapewniają ten sam porządek sortowania. Zawsze jednak można bezpiecznie pozostawić oryginalną implementację
Object.equals(Object)
w stanie nienaruszonym
. Źródło:
3. Jakie metody posiada klasa Collections?
public static <T> boolean addAll(Collection<? super T> c, T... elements)
Metoda dodaje elementy tablicy
elements
do kolekcji
Collection<? super T> c
. Elementy można określać pojedynczo lub jako tablicę. Gdy elementy są określone indywidualnie, metoda ta zapewnia możliwość wygodnego dodania wszystkich elementów do istniejącej kolekcji:
Collections.addAll(flavors, "Peaches 'n Plutonium", "Rocky Racoon");
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key)
public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
Obie metody przeszukują listę przekazaną w parametrze dla obiektu przekazanego w parametrze przy użyciu algorytmu wyszukiwania binarnego. Zwraca indeks elementu jeśli taki element istnieje na liście, w przeciwnym wypadku zwraca indeks pierwszego elementu listy większy niż
key
, jeśli wszystkie elementy są mniejsze niż . Przed użyciem tych metod listy należy posortować. W pierwszym przypadku są one sortowane rosnąco, w „naturalnej” kolejności elementów listy (tak samo jak przy użyciu ). W drugim przypadku lista musi być posortowana rosnąco w kolejności podanej przez przekazany komparator (taka sama kolejność jak przy użyciu [tutaj "z" to komparator z parametrów opisywanej metody])
Preambuła: mechanizm generyczny w języku zapewnia sprawdzanie typu w czasie kompilacji.
Zwykle to wystarczy, ale zdarzają się przypadki, gdy tak nie jest.
Przykładowo przenosimy naszą kolekcję do kodu biblioteki, gdzieś nam nieznanego i bardzo zależy nam na tym, aby kod tej „obcej biblioteki” nie wstawiał do naszej kolekcji elementu niewłaściwego typu.
Jest to możliwy problem nr 1. Możliwy problem nr 2 jest następujący.
Załóżmy, że nasz program wysyła nam komunikat
informujący, że do kolekcji wstawiono element niewłaściwego typu.
Niestety, ten wyjątek może zostać zgłoszony w dowolnym momencie po wstawieniu nieprawidłowego elementu i zwykle daje nam niewiele lub wcale informacji o źródle problemu. Stosując metodę metodyczną możemy uchronić się od problemów pierwszego i drugiego, ponieważ ta metoda tworzy kolekcję, którą można zweryfikować w czasie wykonywania. Rozwiązywanie problemu numer dwa za pomocą tej metody: Na przykład mamy coś takiego i wypada .
key
list.size()
Collections.sort(list)
Collections.sort(list, c)
public static <E> Collection<E> checkedCollection(Collection<E> c, Class<E> type)
ClassCastException
checkedCollection
ClassCastException
Collection<String> c = new HashSet<String>();
Powyższy kod można tymczasowo zastąpić:
Collection<String> c = Collections.checkedCollection(
new HashSet<String>(), String.class);
Kiedy ponownie uruchomimy program, lokalizujemy linię kodu, która wstawia do naszej kolekcji element niewłaściwego typu. Moim zdaniem pokrewne metody:
public static <E> List<E> checkedList(List<E> list,Class<E> type)
public static <K,V> Map<K,V> checkedMap(Map<K,V> m, Class<K> keyType,Class<V> valueType)
public static <E> Set<E> checkedSet(Set<E> s,Class<E> type)
public static <K,V> SortedMap<K,V> checkedSortedMap(SortedMap<K,V> m,Class<K> keyType,Class<V> valueType)
public static <E> SortedSet<E> checkedSortedSet(SortedSet<E> s,Class<E> type)
public static <T> void copy(List<? super T> dest,List<? extends T> src)
Metoda kopiuje elementy src do dest. indeksy skopiowanych elementów będą takie same.
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll)
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
public static <T> T min(Collection<? extends T> coll,Comparator<? super T> comp)
public static <T> T max(Collection<? extends T> coll,Comparator<? super T> comp)
metody zwracają element minimalny/maksymalny w kolekcji w kategoriach „porządku naturalnego” (interfejs Comparable) lub kolejności przekazanego komparatora.
public static boolean disjoint(Collection<?> c1,Collection<?> c2)
Zwraca
wartość true , jeśli kolekcje nie zawierają identycznych elementów.
<T> List <T> emptyList(), <K,V> Map <K,V> emptyMap(),
<T> Set <T> emptySet()
– zwróć odpowiednio pustą listę, mapę i zestaw;
<T> void fill(List<? super T> list, T obj)
– wypełnia listę podanym elementem;
int frequency(Collection<?> c, Object o)
– zwraca liczbę wystąpień danego elementu w kolekcji;
<T> List <T> nCopies(int n, T o)
– zwraca listę
n określonych elementów;
<T> boolean replaceAll(List<T> list, T oldVal, T newVal)
– zastępuje wszystkie określone elementy nowymi;
void reverse(List<?> list)
– „odwraca” listę;
void rotate(List<?> list, int distance)
– przesuwa listę cyklicznie o określoną liczbę elementów;
void shuffle(List<?> list)
– tasuje elementy listy;
<T> Set <T> singleton(T o), singletonList(T o), singletonMap(K key, V value)
– stworzyć zestaw, zestawienie i mapę wystawową składającą się z jednego elementu;
<T extends Comparable<? super T>> void sort(List<T> list),
<T> void sort(List<T> list, Comparator<? super T> c)
– sortowanie listy w naturalnej kolejności i
Comparator
odpowiednie jej wykorzystanie;
void swap(List<?> list, int i, int j)
– zamienia elementy listy na określonych pozycjach.
Źródła:
4. Jakie metody posiada klasa Arrays?
Pełną listę metod klasy Arrays można zobaczyć w
dokumentacji . W tym podsumowaniu przytoczę tylko kilka z nich. [przetłumaczyłem metody z dokumentacji i niestety straciłem większość mojego tłumaczenia. Szkoda, a nie chcę tracić czasu na to samo, więc wkleję to, co wygooglowałem]
public static <T> List<T> asList(T... a)
generuje listę na podstawie tablicy. Tablica służy do wewnętrznej reprezentacji listy. Zachowuje to połączenie między listą a oryginalną tablicą: zmiany w tablicy zostaną odzwierciedlone na liście:
String[] a = { "foo", "bar", "baz"};
List<String> list = Arrays.asList(a);
System.out.println(list);
a[0] = "aaa";
System.out.println(list);
zmiany na liście zostaną odzwierciedlone w tablicy:
String[] a = { "foo", "bar", "baz"};
List<String> list = Arrays.asList(a);
System.out.println(list);
list.set(0, "bbb");
System.out.println(Arrays.toString(a));
Jeśli tablica zawiera obiekty, oczywiście zarówno tablica, jak i lista będą odnosić się do tych samych instancji:
Object[] a = { new Object(), new Object(), new Object()};
List<Object> list = Arrays.asList(a);
System.out.println(a[0] == list.get(0));
int binarySearch(параметры)
– przeciążona metoda organizacji wyszukiwania binarnego wartości w tablicach typów pierwotnych i obiektowych. Zwraca pozycję pierwszego dopasowania;
void fill(параметры)
– przeciążona metoda wypełniania tablic wartościami różnych typów i prymitywami;
void sort(parameters) – przeciążona metoda sortowania tablicy lub jej części przy użyciu interfejsu Comparator i bez niego;
static <T> T[] copyOf(T[] original, int newLength)
– wypełnia tablicę o określonej długości, odrzucając elementy lub wypełniając null, jeśli to konieczne;
static <T> T[] copyOfRange(T[] original, int from, int to)
– kopiuje określony obszar tablicy do nowej tablicy;
<T> List<T> asList(T… a)
– metoda kopiująca elementy tablicy do obiektu typu List<T>.
Źródło:
5. Jaka jest nazwa sortowania używanego podczas wywoływania Collections.sort()?
Z dokumentacji : Implementacja jest adaptacją sortowania list Tima Petersa w Pythonie (TimSort). Ta implementacja zrzuca listę do tablicy, sortuje ją, następnie wykonuje iterację po liście i ponownie ładuje każdy element listy z odpowiedniego elementu tablicy. Pozwala to uniknąć złożoności n*n log(n), która mogłaby powstać przy próbie bezpośredniego sortowania połączonej listy.
Z wiki : Timsort to hybrydowy algorytm sortowania łączący sortowanie przez wstawianie i sortowanie przez scalanie, opublikowany w 2002 roku przez Tima Petersa. Timsort jest obecnie standardowym algorytmem sortowania w Pythonie, OpenJDK 7 i zaimplementowanym w Androidzie JDK 1.5. Główną ideą algorytmu jest to, że w świecie rzeczywistym sortowalne tablice danych często zawierają uporządkowane podtablice. Na takich danych Timsort działa znacznie szybciej niż wiele algorytmów sortujących.
10. Co to jest iterator?
Interfejs wprowadzony w wersji JDK 1.2 języka Java
java.util.Iterator
pozwala na iterację klas kontenerów. Każdy Iterator implementuje metody
next()
i
hasNext()
opcjonalnie może obsługiwać
remove()
. Iteratory są tworzone przez odpowiednie klasy kontenerów, zwykle przez klasę
iterator()
. Metoda
next()
przesuwa iterator do następnej wartości i zwraca określoną wartość do iteratora. Po utworzeniu iterator wskazuje specjalną wartość przed pierwszym elementem, więc pierwszy element można pobrać dopiero po pierwszym wywołaniu
next()
. Aby określić moment, w którym wszystkie elementy w kontenerze zostały poddane iteracji, stosuje się metodę testową
hasNext()
. Poniższy przykład ilustruje proste użycie iteratorów:
Iterator iter = list.iterator();
while (iter.hasNext())
System.out.println(iter.next());
W przypadku kolekcji typów, która to obsługuje, metoda iteratora
remove()
usuwa ostatni „odwiedzony” element z kontenera. Prawie wszystkie inne typy modyfikacji kontenera podczas iteracji są niebezpieczne. Dodatkowo for
java.util.List
istnieje
java.util.ListIterator
z podobnym API, ale umożliwia iterację do przodu i do tyłu, podając definicję bieżącego indeksu na liście i przenosząc się do elementu po jego pozycji.
Źródło:
Część 2
GO TO FULL VERSION