добавянето или изтриването на елемент (с изключение на последна позиция) е скъпа операция
най-ефективни от гледна точка на използвана памет*
размерът им е фиксиран при инициализацията
бърз достъп на елемент по индекс: O(1)
търсенето на елемент по стойност е бавно: О(N) за произволен масив O(logN) за сортиран масив
Класа Arrays
Arrays дефинира методи за работа с масиви
Arrays.fill - метод за запълване на масиви е една стойност Arrays.sort - метод за сортиране на масиви Arrays.toString - метод за текстово представяне на масиви
Колекции
Java предоставя т.нар. collections framework, съдържащ интерфейси, имплементации и алгоритми върху най-използваните структури от данни
За разлика от масивите,
размерът им е динамичен
съдържат само референтни типове
Почти всички интерфейси и класове се намират в пакета java.util
Итератори
Итераторите предоставят унифициран начин за обхождане на елементите на дадена колекция.
Колекциите (както и масивите) могат да се обхождат с foreach loop
В java са дефинирани интерфейсите поведението на който се имплементира от всички колекции.
Метода next() връща следващия елемент в колекцията
Методът remove() премахва от колекцията елемента, последно върнат от next()
Ако колекцията бъде модифицирана докато бъде итерирана, по какъвто и да е начин, различен от извикване на remove() на итератора, поведението на итератора е недефинирано води до грешка (ConcurrentModificationException)
Основни структури от данни
Масиви
Свързани списъци
Хеш таблици
Дървета
Предефинирани методи за работа с java.util.Collection
Collection е интерфейс, за всички колекции който го имплементират могат да се използват методите:
Пример
Обхождане на колекции
Предефинирани методи за работа с List
List е интерфейс, за всички колекции който го имплементират могат да се използват методите:
Имплементации на List
ArrayList - resize-ващ се (динамичен) масив
LinkedList - двойно свързан списък
Vector - resize-ващ се (динамичен) масив. Synchronized. Legacy
Stack - наследява Vector. Legacy -> замества се от Dequeue
Предефинирани методи за работа с Queue
Queue е интерфейс, за всички колекции който го имплементират могат да се използват методите:
Имплементации на Queue
PriorityQueue - heap (пирамида)
LinkedList
ArrayDeque - resize-ващ се (динамичен) масив
Предефинирани методи за работа с Set
Set е интерфейс, за всички колекции който го имплементират могат да се използват методите:
Имплементации на Set
TreeSet - TreeMap. Червено-черно дърво
конструктори
HashSet - хеш таблица
конструктори
LinkedHashSet - хеш таблица + свързан списък
EnumSet - битов масив
Операции над множества със Set
Предефинирани методи за работа с Map
Map е интерфейс, за всички колекции който го имплементират могат да се използват методите:
Колекция съпоставяща обект ключ към обект стойност.
Не може да съдържа дублирани ключове.
При опит за добавяне на съществуващ ключ се променя стойноста
Обхождане на колекции Map
Имплементации на Map
HashMap - хеш таблица
LinkedHashMap - хеш таблица + свързан списък
EnumMap - битов масив
TreeMap - червено-черно дърво
Колекции с наредба vs Колекции без наредба
TreeMap/TreeSet - червено-черни дървета. Запазват естествена наредба. Елементите трябва да имплементират интерфейса Comparable (или да се подава имплементация на Comparator). Логаритмична сложност за повечето операции
HashMap/HashSet - хеш таблици. Нямат естествена наредба. Елементите трябва да имплементират методите hashCode() и equals(). Константна сложност за повечето операции
Generics
трябва експлицитно да кастваме, което е досадно
Опасн е защото има вероятност да сгрешим в предположението си за типа и cast-ът да "гръмне" с ClassCastException по време на изпълнение
Много по-удобно
програмистът може да изрази намерението си да ползва определен тип и компилаторът може да гарантира коректността на програмата за този тип
Пример
List<E> - // Чете се "списък от E"
Не-generic кутия
Generic кутия
Създаване на инстанции
Конвенция за именуване на параметрите за тип:
E - Element
T - Type
K - Key
V - Value
N - Number
S, U, V etc. - 2-ри, 3-ти, 4-ти тип
Generic методи
Могат да ползват типовите параметри на класа/метода
Могат да добавят нови параметри за тип, недекларирани от класа
Новите параметри за тип са видими единствено за метода, който ги декларира
Generic методите могат да са статични, нестатични или конструктори
Пример
Generic типове и наследяване
Integer is-a Object
Integer is-a Number
Double is-a Number
Box is-not-а Box (Техният общ родител е Object)
Ограничени (bounded/restricted) Generic типове
Може да се специфицира, че generic тип е съвместим само с даден тип или негови наследници/имплементации (upper bound).
Generic и колекции
Всички ипове колекции имат Generic еквивалент което позволява използването на предефинираните алгоритми върху колекции с програмно дефинирани обекти.
За да могат да бъдат използвани е необходимо дефиниране на:
интерфейса Comparable
метода hashCode()
метода equals()
Сортиране на колекции
Класа Collections съържа функции за сортиране на колекции.
Функцията Collections.sort приема като входен параметър функцията която трябва да се сортира.
Критерия по който ще се сортира колекцията се подава като втори параметър посредством обект от клас имплементиращ интерфейса Comparator.
Пример
Метода compare служи за сравнение на два обекта от колекцията. Той връща като резултат
//Интерфейси Iterable
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
//Интерфейси Iterable
public interface Iterable<T> {
Iterator<T> iterator();
}
//дефиниране на колекция от интерфейса Collection
Collection<Integer> integers; //колекция от тип int
Collection<Book> books; //колекция от тип книги
//броя на елементите в колекцията
int size()
//Проверка дали е празна молекцията
boolean isEmpty()
//Проверка дали колекцията съдържа елемента
boolean contains(Object element)
//Добавяне на елемент в колекция
boolean add(E element)
//Премахване на елемент от колекция
boolean remove(Object element)
//Извличане на итератора на колекцията
Iterator<E> iterator()
//Проверка дали всички елементи се съдържт в колекцията
boolean containsAll(Collection<?> c)
//Докабяне на списък от обекти
boolean addAll(Collection<? extends E> c)
//Премахване на сисък от елементи
boolean removeAll(Collection<?> c)
//Премахване на всички които не присъстват в сисъка от елементи
boolean retainAll(Collection<?> c)
//Почистване на паметта към която сочи колекцията
void clear()
//Преобразуване на колекцията в масив от класа Ojbect
Object[] toArray()
//Преoбразуване на колекцията в масив от програмно дефиниран клас
<T> T[] toArray(T[] a)
//създаване на списък с дробни числа
List<Float> nums = Arrays.asList(4.999f, 0.271f, 7.1f, -1f);
//Обхождане чрез enhanced for-loop:
for (float current : nums) {
System.out.printf("%.2f%n", current);
}
//Обхождане чрез итератор
Iterator<Float> iterator = nums.iterator();
while (iterator.hasNext()) {
System.out.printf("%.2f%n", iterator.next());
}
boolean add(E e)
boolean contains(Object o)
E get(int index)
int indexOf(Object o)
boolean remove(Object o)
E remove(int index)
int size()
boolean isEmpty()
Object[] toArray()
List<E> subList(int fromIndex, int toIndex)
// Добавя елемент в края на опашката
boolean offer(E e)
// Извлича първия елемент от опашката
E peek()
// Извлича и премахва първия елемент от опашката
// Връща null ако опашката е празна
E poll()
// Премахва и извлича първия елемент от опашката
// Ако опашката е празха хвърля NoSuchElementException
E remove()
Set<String> one = new HashSet<>();
one.add("foo");
one.add("bar");
Set<String> two = new HashSet<>();
two.add("foo");
two.add("baba");
Set<String> union = new HashSet<>(one);
union.addAll(two); // union, съюз, обединение = [baba, bar, foo]
Set<String> intersection = new HashSet<>(one);
intersection.retainAll(two); // intersection, пресичане, обща част = [foo]
Set<String> difference = new HashSet<>(one);
difference.removeAll(two); // difference, разлика, различна част = [bar]
V put(K key, V value)
V get(Object key)
V remove(Object key)
boolean containsKey(Object key)
int size()
boolean isEmpty()
Set<K> keySet()
Collection<V> values()
// множеството от ключовете
Set<Integer> keys = map.keySet();
// колекция от стойностите
Collection<String> values = map.values();
// Set<Entry<Integer, String>> s = map.entrySet();
List list = new LinkedList();
list.add(new Integer(1));
Integer i = list.iterator().next(); //неможе да се опредили типа на обекта върнат от метода next()
List list = new LinkedList();
list.add(new Integer(1));
Integer i = (Integer) list.iterator().next(); //кастване към класа Integer
public class Box {
private Object value;
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
public class Box<Т> {
private Т value;
public Т getValue() {
return value;
}
public void setValue(Т value) {
this.value = value;
}
}
// пълен сиснтаксис
Box<Integer> integerBox = new Box<Integer>();
// кратък синтаксис
Box<Integer> integerBox = new Box<>();
public class Pair<K, V> {
private K key;
private V value;
// Generic конструктор
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
// Generic методи
public K getKey() { return key; }
public void setKey(K key) { this.key = key; }
public V getValue() { return value; }
public void setValue(V value) { this.value = value; }
}
//клас с общо предназначение
public class Util {
// Generic статичен метод
public static <K, V> boolean areEqual(Pair<K, V> p1, Pair<K, V> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
public <T extends Number> List<T> fromArrayToList(T[] a) {
// [...]
}
// Ако типовете са повече от един, те се разделят с &, като в този случай
// най-много един може да бъде клас (останалите трябва да са интерфейси)
// и ако има клас, той трябва да стои първи в списъка.
// Обърнете внимание, че въпреки че Comparable е интерфейс, а не клас,
// ключовата дума е пак extends.
public <T extends Number & Comparable> List<T> anotherMethod(T[] a) {
// [...]
}
public class SortById implements Comparator<EMailImpl> {
@Override
public int compare(EMailImpl o1, EMailImpl o2) {
return o1.compareToId(o2.getUsername());
}
}