воскресенье, 23 марта 2014 г.

Немного необходимого в Java.

Немного необходимого в 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) {
    // do stuff
  }
}
эквивалентен этому: 
?
1
2
3
public synchronized void blah() {
  // do stuff
}
Однако 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
Контейнеры бывают двух видов:
  1. Коллекции (List, Set, Queue)
  2. Ассоциативный массив (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
// Outer.java
public class Outer {
    Outer() {
        Inner i = new Inner();
        i.innerMethod();
    }
    // Inner class
    private class Inner {
        Inner() {}
        public void innerMethod() {
            // Do something.
        }
    }
}
Анонимный внутренний класс - это класс, который определен в методе другого класса и может быть использован только один раз - там, где он определен. Примером анонимного внутреннего класса часто является реализация обработчика какого-либо события.

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();

В общем как то так,что то писал сам,что то дергал с других ресурсов.
Получилась не слишком длинная,но вполне возможно, что полезная шпаргалка.