Ссылочные типы Java

110
11 августа 2019, 19:00

Я начал учить Java и не могу понять один момент. Просматривая очередной видеоурок я услышал, что "При создании переменной одного из ссылочных типов происходит создание ячейки памяти, содержащей ссылку на произвольный объект в памяти. Когда мы присваиваем значение этой ссылочной переменной в другую переменную, происходит копирование ссылки и мы получаем вторую ссылку, указывающую на тот же объект"

Далее сказано, что "Если объект модифицировать через вторую ссылку, то изменения будут видны и через первую ссылку, потому что это тот же самый объект"

Я это понял так, что в памяти есть один и тот же объект, на который могут ссылаться несколько переменных. Соответственно при изменении одной переменной, ссылающейся на данный объект, будут изменены и значения всех других переменных, ссылающихся на этот же объект

Решив проверить это опытным путем я тут же написал короткий код:

public class Main {
    public static void main(String[] args) {
    String s1 = "Hello";
    String s2 = s1;
    s2 += "!";
    System.out.println("s1 = " + s1 + "\n" + "s2 = " + s2);
    }
}

Сначала я создая переменную s1 ссылочного типа String и присваиваю ей произвольное значение. После этого, создаю новую переменную s2 и приравниваю ее к s1. Как я понял, должно происходить копирование ссылки, и в итоге обе переменные должны ссылаться на один и тот же объект строки в памяти. Соответственно, при изменении этого объекта в памяти через одну переменную, изменения должны быть видны и через другую, но этого не происходит - ниже представлен вывод этой программы

>>> s1 = Hello
>>> s2 = Hello!

Почему изменение объекта, на который ссылается s1 не привело к изменению объекта, на который ссылается s2, учитывая, что они должны ссылаться на один и тот же объект в памяти?

Answer 1

Объекты типа String в Java - неизменяемы. Когда вы вносите изменение в объект типа String с помощью одного из методов этого класса или с помощью конкатенации (в вашем случае - для изменения строки используется конкатенация: s2 += "!";) - тогда создается НОВЫЙ объект класса String который будет представлять собой (по содержанию символов) старую строку с внесенными изменениями. В строке s2 += "!"; вы как раз создаете ещё одну строку и присваиваете переменной s2 ссылку на эту новую строку. При этом ссылка s1 попрежнему ссылается на объект строки созданный вами раннее.

Попробуйте провести ваш маленький эксперимент с типом StringBuilder (этот тип данных представляет собой как раз таки изменяемую строку).

Answer 2

Объект String является неизменяемым. Несмотря на то, что переменные типа String являются ссылочными, при их изменении создается новый объект и новая переменная по ссылке указывает уже на него(а не на тот объект, который был взят для изменения).

Типы переменных

Примитивные и ссылочные

Примитивные типы Java не являются объектами. К ним относятся:

boolean - булев тип, может иметь значения true или false

byte - 8-разрядное целое число

short - 16-разрядное целое число

int - 32-разрядное целое число

long - 64-разрядное целое число

char - 16-разрядное беззнаковое целое, представляющее собой символ UTF-16 (буквы и цифры)

float - 32-разрядное число в формате IEEE 754 с плавающей точкой

double - 64-разрядное число в формате IEEE 754 с плавающей точкой

Все остальные типы являются ссылочными. Подробнее здесь

Изменяемые и неизменяемые

Тип String неизменяемый. При попытке изменения значения переменных этого типа, в памяти будет создаваться новый объект

Изменяемым типом является к примеру ArrayList или StringBuilder, использующийся ниже в примере

Подробнее здесь

Желаемое поведение программы достигается, при использовании ссылочных, изменяемых типов(String - ссылочный, неизменяемый)

Перепишем программу с использованием изменяемого аналога String - StringBuilder:

public class Main {
    public static void main(String[] args) {
    // Создаём изменяемый объект типа `StringBuilder`
    StringBuilder s1 = new StringBuilder("Hello");
    // s2 - ссылка на s1
    StringBuilder s2 = s1;
    // `StringBuilder` - изменяемый,
    //  поэтому нового объекта не создается
    s2.append("!");
    // При изменении объекта, изменились значения
    // и всех ссылающихся на него переменных
    System.out.println("s1 = " + s1 + "\n" + "s2 = " + s2);
    }
}

Вывод:

>>> s1 = Hello!
>>> s2 = Hello!

Подробнее про StringBuilder здесь

READ ALSO
Диалог с Сервером со стороны Kлиента

Диалог с Сервером со стороны Kлиента

Нужно чтобы клиент постоянно находился в режиме ожидания ввода команд со стороны пользователяЭти команды затем отправляются на сервер

113
Не отскакивает тело box2d

Не отскакивает тело box2d

При столкновении с другим телом ball либо останавливается, либо двигается вдоль негоВроде как это может происходить из-за неправильного world scale,...

122
Создание файла MS Word при нажатии на кнопку в графическом интерфейсе

Создание файла MS Word при нажатии на кнопку в графическом интерфейсе

Пытаюсь получить строковую переменную из "TextField" и передать ее в создаваемый файл MS Word

122
Не могу получить данные из базы данных

Не могу получить данные из базы данных

Пробую делать мини приложение, что-то типа доски объявленийНи как не получается у меня сделать поиск по фильтру

121