-
Notifications
You must be signed in to change notification settings - Fork 3
References
Попробую суммировать все, что знаю про ссылки в Java
###Ссылки Прежде всего обратимся к Java-doc:
An object is a class instance or an array.
The reference values (often just references) are pointers to these objects, and a special null reference, which refers to no object.
Ссылки крайне важны в контексте сборки мусора, т.е при работе GC. Да, GC сам парень умный и разбирается когда, где и что удалять без нас. Но мы же должны как-то влиять на его решения? Чтобы помочь ему в Java имеется несколько типов ссылок.
В Java есть несколько типов ссылок:
- strong reference
- soft reference
- weak reference
- phantom reference
Разберем подробнее их.
Всегда, когда мы пишем new
- мы создаем strong
reference. Объект не может быть удален GC до тех пор, пока у него есть хотя бы одна strong ссылка.
Остальные ссылки в пакете java.lang.ref
.
Объекты созданные с SoftReference
будут уничтожены GC в случае, если JVM требует память. Все soft references объекты будут собраны GC перед(до того как) JVM кинет OutOfMemoryError
. SoftReference
используются для кэшей, но я их никогда не использовал, если вдруг придется - допишу.
WeakReference
могут быть удалены GC когда он посчитает нужным, при этом не важно, будет ли достаточно памяти или нет. Т.е когда на объект нет soft и strong ссылок - он может быть финализирован(finalize), удален GC.
Объекты созданные через PhantomReference
, Если на объект есть только фантомная ссылка, то будет выполнена попытка утилизации данного объекта при сборке мусора. Сам объект при этом не будет удален из памяти до тех пор, пока на него существует фантомная ссылка или данная фантомная ссылка не очищена с помощью вызова метода clear().
Сразу скажу - я пока что не пользовался никакими ссылками, кроме strong
. И это тема для отдельной статьи. Ниже я рассмотрю только то, что мы можем делать с обычными ссылками.
###Рассмотрим strong references.
- Присваивание.
- Доступ к полям объекта
- Вызов методов
- Приведение типа
- Конкатенация строк ('+' operator)
- Проверка на принадлежность к типу - the instanceof operator
- Сравнение - '==' and '=!'
- условный оператор ? :
У каждого объекта есть счетчик строгих ссылок . Когда на объект появляется еще одна ссылка - счетчик увеличивается. Когда мы убираем ссылку с объекта или присваиваем null
- счетчик уменьшается. Если объект не имеет ссылок - он становится доступным для GC.
Тип объекта контролируется по ссылке. Контроль происходит в compile time
.
Оператор конкатенации строк требует, чтобы хотя бы один операнд был строкой(String). Если это так - второй операнд конвертится к строке благодаря toString()
методу(если ссылка null
или toString() возвращает null
- будем работать со строкой "null"
) и после этого мы создаем новый объект String с результатом конкатенации.
Оператор, который позволяет определить тип Object. Если у нас variable = null
-результат variable instance of Type
будет всегда false
. Важный момент - childObjectClass instanceof parentObjectClass
будет true
. Потому что instanceOf - это наследование is a
(является).
Если сравниваемые объекты разных типов, то один из них должен иметь возможность приведения к другому, иначе такой код не скомпилируется.
Как передаются параметры-объекты. Рассмотрим пример:
class Example {
public void methodM() {
MyExampleClass link1 = new MyExampleClass();
method(link1);
}
public void method(MyExampleClass link2) {
//2
//some work
}
class MyExampleClass {
int x;
}
}
Видим, что тут мы создаем ссылку link1, ей присваиваем объект какой-то. Передаем ссылку в некий method. Теперь вопрос, а сколько у нас ссылок в //2 на объект наш?
Немного не очевидно, но их две. И вот почему. Создается еще одна ссылка, в нее копируется область памяти первой ссылки, отсюда у нас появляется две ссылки, которые указывают на один и тот же объект. При этом, если мы в методе изменим наш объект - он изменится и во вне метода, что логично - мы через ссылку получаем объект и с ним работаем. Но! Если мы ссылке в методе присвоим какой-то другой объект, то наша первая ссылка не изменится. Т.е если я в методе link2 присвою новый объект, то link2 будет указывать на этот объект, а link1 будет все также указывать на мой старый объект. По сути ссылка в java - это штука, которая сама является оберткой над именно ссылкой в понимании с/с++, надо кусочком памяти ее.
Поэтому в java, если мы хотим написать что-то по типу swap-метода, который меняет местами два объекта - не совсем тривиально(не нужно?). Если мы хотим написать что-то типа:
public void swap(String a, String b) {
String tmp = a;
a = b;
b = tmp
}
То, как я и говорил выше, мы поменяем местами ТОЛЬКО в методе, как только метод закончится - все вернется на круги своя. Мы никак не работаем со ссылками извне. Но что делать, если мы хотим реализовать такой метод? Все просто, надо создать объект-обертку с полем нашей строки и передавать уже этот объект, а там менять.
Если у нас final
в методе - то мы просто не можем присвоить этой ссылке другой объект, но сам объект по этой ссылке мы изменить можем. Т.е final - это гарантия того, что в методе я буду работать только с тем объектом, который передаю в вызове метода и никаким иным. Но в процессе работы - я могу изменить внутренности объекта.
//todo наверное надо переписать и про типы ссылок подробнее