Skip to content

Latest commit

 

History

History
117 lines (91 loc) · 8.83 KB

reference.md

File metadata and controls

117 lines (91 loc) · 8.83 KB

Ссылки

Прежде всего посмотрим что говорит нам 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.

Что значит примерно следующее: Объект - это инстанс класс или массив. Значение ссылки - это указатель на объект или специальная null ссылка, указывающая на отсутствие объекта.

В Java ссылки крайне важны в контексте сборки мусора, т.е при работе GC. При работе GC учитывает следующие типы ссылок:

  • strong reference
  • soft reference
  • weak reference
  • phantom reference

Разберем подробнее их.

Всегда, когда мы пишем new - мы создаем strong reference. Объект не может быть удален GC до тех пор, пока у него есть хотя бы одна strong ссылка.

Объекты созданные с SoftReference будут уничтожены GC в случае, если JVM требуется больше памяти. Все soft references объекты будут собраны GC перед(до того как) JVM кинет OutOfMemoryError. SoftReference используются для различных кэшей.

WeakReference могут быть удалены GC когда он посчитает нужным, при этом не важно, будет ли достаточно памяти или нет. Т.е когда на объект нет soft и strong ссылок - он может быть финализирован(finalize), удален GC.

Небольшой пример:

public class WeakReferenceExample {
    public static void main(String[] args) {
        WeakReference<Integer> ref = new WeakReference<>(1000);
        System.out.println("Before gc: " + ref.get());

        for (int i = 0; ref.get() != null; i++) {
            System.gc();
            System.out.printf("After gc, iteration: %d, ref: %d", i, ref.get());
        }
    }
}

Что выведет нам:

Before gc: 1000
After gc, iteration: 0, ref: null

Т.е после первой просьбы к GC объект удалили.

Объекты созданные через PhantomReference - если на объект есть только фантомная ссылка, то будет выполнена попытка утилизации данного объекта при сборке мусора. Сам объект при этом не будет удален из памяти до тех пор, пока на него существует фантомная ссылка или данная фантомная ссылка не очищена с помощью вызова метода clear().

Strong reference

Что должна уметь ссылка?

  • Присваивание.
  • Доступ к полям объекта
  • Вызов методов
  • Приведение типа
  • Конкатенация строк ('+' operator)
  • Проверка на принадлежность к типу - instanceof.
  • Сравнение - '==' and '=!'
  • условный оператор ? :
Присваивание

У каждого объекта есть счетчик строгих ссылок . Когда на объект появляется еще одна ссылка - счетчик увеличивается. Когда мы убираем ссылку с объекта или присваиваем null - счетчик уменьшается. Если объект не имеет ссылок - он становится доступным для GC. Тип объекта контролируется по ссылке. Контроль происходит в compile time.

String concatenation(Конкатенация)

Оператор конкатенации строк требует, чтобы хотя бы один операнд был строкой. Если это так - второй операнд конвертится к строке благодаря toString() методу(если ссылка null или toString() возвращает null - будем работать со строкой "null") и после этого мы создаем новый объект String с результатом конкатенации.

Instanceof operator

Оператор, который позволяет определить тип 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 - это штука, которая сама является оберткой над именно ссылкой в понимании C/C++, надо кусочком памяти ее.

Поэтому в java, если мы хотим написать что-то по типу swap-метода, который меняет местами два объекта - не совсем тривиально(не нужно?). Если мы хотим написать что-то типа:

public void swap(String a, String b) {
  String tmp = a;
  a = b;
  b = tmp
}

То, как я и говорил выше, мы поменяем местами ТОЛЬКО в методе, как только метод закончится - все вернется на круги своя. Мы никак не работаем со ссылками извне. Но что делать, если мы хотим реализовать такой метод? Все просто, надо создать объект-обертку с полем нашей строки и передавать уже этот объект, а там менять.

Если у нас final в методе - то мы просто не можем присвоить этой ссылке другой объект, но сам объект по этой ссылке мы изменить можем. Т.е final - это гарантия того, что в методе я буду работать только с тем объектом, который передаю в вызове метода и никаким иным. Но в процессе работы - я могу изменить внутренности объекта.

//todo наверное надо переписать и про типы ссылок подробнее