Немного необходимого в Java.
Решил написать несколько теоретический пост,про основные понятия в Java,которые нужно знать каждому(по моему мнению).
Есть много вроде простых вопросов,на которые очень мало кто может ответить, еще их достаточно часто могут спросить и на собеседованиях)
В общем не будет лишним заметка.
Поехали:
Самый популярный вопрос:
Что такое Hashmap и как он работает?
Да все просто на самом деле.
Map - интерфейс, описывающий классы, предназначенные для хранения пар объектов. Один из объектов пары должен быть уникальным - называется "ключом" (key), второй объект, необязательно уникальный, называется "значением" (value). Всю пару называют "записью" (entry).
Уникальный - значит не равный другим ключам. Как определить "равность"? Достаточно знать, что ключи в Map сравниваются по методу equals(), и при попытке добавить в Map запись с не уникальным ключом предыдущая запись будет затерта новой.
Как HashMap устроен внутри?
Внутри HashMap - это массив. Элементы массива в документации называются бакетами (buckets). В бакете хранится первый элемент связанного списка.Таким образом, HashMap внутри - массив связанных списков. Элемент связанного списка - объект класса Entry, содержит ключ, значение и ссылку на следующий Entry.
Что происходит при добавлении записи?
На следующем шаге, рассчитывается хеш-значение используя хеш-код ключа, получаемый вызовом метода hashCode(). Это хеш-значение используется для вычисления позиции в массиве, куда будет помещен объектEntry. Дизайнеры JDK предполагали, что плохо написанная функция hashCode() может вернуть слишком высокое или слишком низкое значение хеш-кода. Для решения этой проблемы, они ввели другую hash() функцию, и передали в нее значение хеш-кода объекта, чтобы привести хеш-значение в соответствие с размером массива.Теперь вызывается функция indexFor(hash, table.length), для вычисления точной позиции, куда будет помещен объект Entry
Далее, найдя нужный бакет, запись помещается в соответствующий связанный список.
А как искать элемент?
Поиск производится по ключу (ключ для поиска). Опять же по hashcode() ключа находим нужный бакет. Нашли бакет - значит нашли нужный нам связанный список. Далее проходим по списку и сравниваем ключи элементов списка с нашим ключом для поиска. Сравнение производим по функции equals(). Вернула функция true - значит нашли.
И для чего все это нужно?
Для ускорения работы. В первую очередь ускорение поиска. Напомню, соответствие между hashcode ключа и бакетом не хранится, а вычисляется. Математические вычисления - это быстро. Далее, сравнивать объекты по equals() все же придется, но количество этих объектов ограничено.
Есть такие понятия как loadfactor и capacity-но они простые,даже писать не буду)
Как то много получилось про HashMap сейчас попробую короче укладываться.
В чем отличие между static synchronized и просто synchronized?
Использование слова synchronize на static-методе помечает весь класс как synchronize, т.е. такая запись:
1
2
3
|
synchronized static void foo() {
...
}
|
равнозначна такой:
1
2
3
4
5
|
static void foo() {
synchronized(SomeClass.class) {
...
}
}
|
А такая:
1
2
3
|
synchronized void foo() {
...
}
|
такой:
1
2
3
4
5
|
void foo() {
synchronized(this) {
...
}
}
|
Что значит synchronized(this)?
Семантически этот код:
1
2
3
4
5
|
public void blah() {
synchronized (this) {
}
}
|
эквивалентен этому:
1
2
3
|
public synchronized void blah() {
}
|
Однако synchronized(this) использовать не рекомендуется. Почему? Об этом можно почитать тут .
Что означают ключевые слова volatile и transient.
Определение переменной с ключевым словом volatile(«изменчивый») означает, что значение переменной будет изменяться несколькими потоками.
Переменная помеченая словом transient не будет сериализоваться и соответственно при десериализации её значение будет установлено значением по умолчанию.
Условия сериализации объектов?
Свойства класса должны быть сериализуемы и класс должен реализовывать маркирующий интерфейс Serializable. Не лишним будет вспомнить про serialVersionUID и его значение по умолчанию.
Можно ли передать объект в synchronized?
Да. Например очень популярна вот такая несложная конструкция:
1
2
3
4
5
6
7
8
9
|
private final Object _SyncObject = new Object();
...
public void run() {
...
synchronized(_SyncLock) {
...
}
...
}
|
Работа со ссылками (weak и strong reference).
Об этом можно почитать тут.
Как сделать ArrayList синхронизированым в одну строку?
1
|
List<Record> s_list = Collections.synchronizedList(list);
|
Контракт между equals и hashCode.
Если equals возвращает true, то hashCode должен вернуть одно и то же значение. Обратное не верно.
Collections
Контейнеры бывают двух видов:
- Коллекции (List, Set, Queue)
- Ассоциативный массив (Map)
К популярным реализациям контейнеров стоит отнести: ArrayList, LinkedList, HashSet, TreeSet, LinkedHashSet, HashMap, TreeMap, LinkedHashMap.
В ArrayList и LinkedList элементы хранятся в порядке вставки. Различаются скоростью выполнения и количеством тех или иных операций: ArrayList имеет оптимизированый доступ к элементам списка, но обладает низкой производительностью при добавлении/удалении элементов в середину списка. LinkedList - наоборот.
HashSet обеспечивает наибольшую производительность при выборке элементов. TreeSet хранит элементы отсортированными по возрастанию в порядке сравнения. LinkedHashSet хранит элменты в порядке добавления.
HashMap обеспечивает наибольшую производительность. TreeMap хранит ключи отсортированными. LinkedHashMap хранит ключи в порядке вставки, но обеспечивает скорость HashMap.
Inner classes
Внутренний класс - класс, который объявлен внутри другого класса, например:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class Outer {
Outer() {
Inner i = new Inner();
i.innerMethod();
}
private class Inner {
Inner() {}
public void innerMethod() {
}
}
}
|
Анонимный внутренний класс - это класс, который определен в методе другого класса и может быть использован только один раз - там, где он определен. Примером анонимного внутреннего класса часто является реализация обработчика какого-либо события.
Serialization
Сериализация это процесс сохранения состояния объекта в последовательность байт;десериализация это процесс восстановления объекта, из этих байт. Java Serialization API предоставляет стандартный механизм для создания сериализуемых объектов.
Сохранение объекта:
1
2
3
4
5
6
7
8
9
|
FileOutputStream fos = new FileOutputStream("temp.out");
ObjectOutputStream oos = new ObjectOutputStream(fos);
TestSerial ts = new TestSerial();
oos.writeObject(ts);
oos.flush();
oos.close();
|
Восстановление объекта:
1
2
3
|
FileInputStream fis = new FileInputStream("temp.out");
ObjectInputStream oin = new ObjectInputStream(fis);
TestSerial ts = (TestSerial) oin.readObject();
|
В общем как то так,что то писал сам,что то дергал с других ресурсов.
Получилась не слишком длинная,но вполне возможно, что полезная шпаргалка.