Настройка переменной Java String - ссылка или значение? - PullRequest
17 голосов
/ 29 апреля 2011

Следующий фрагмент кода Java взят из практического экзамена AP Computer Science.

String s1 = "ab";
String s2 = s1;
s1 = s1 + "c";
System.out.println(s1 + " " + s2);

Вывод этого кода - "abc ab" в BlueJ.Однако один из возможных вариантов ответа - «abc abc».Ответ может быть либо в зависимости от того, устанавливает ли Java String ссылку как примитивные типы (по значению) или как Objects (по ссылке).

Чтобы дополнительно проиллюстрировать это, давайте рассмотрим пример с примитивными типами:

int s1 = 1;
int s2 = s1; // copies value, not reference
s1 = 42;

System.out.println(s1 + " " + s2); // prints "1 42"

Но, скажем, у нас есть BankAccount объекты , которые удерживают остатки.

BankAccount b1 = new BankAccount(500); // 500 is initial balance parameter
BankAccount b2 = b1; // reference to the same object
b1.setBalance(0);
System.out.println(b1.getBalance() + " " + s2.getBalance()); // prints "0 0"

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

Если Java передает строковые переменные как примитивный тип, ответом является «abc ab».Однако если Java обрабатывает строковые переменные как ссылки на любой другой объект, ответом будет «abc abc»

Какой, по вашему мнению, правильный ответ?

Ответы [ 9 ]

27 голосов
/ 29 апреля 2011

Java-строки являются неизменяемыми, поэтому ваше переназначение фактически заставляет вашу переменную указывать на новый экземпляр String, а не изменять значение String.

String s1 = "ab";
String s2 = s1;
s1 = s1 + "c";
System.out.println(s1 + " " + s2);

в строке 2, s1 == s2 И s1.equals (s2). После вашей конкатенации в строке 3 s1 теперь ссылается на другой экземпляр с неизменным значением «abc», поэтому ни s1 == s2, ни s1.equals (s2).

13 голосов
/ 29 апреля 2011

Разница между вашим BankAccount и строкой заключается в том, что строка является неизменной. Не существует такой вещи, как setValue () или setContent (). Эквивалентный пример с вашим банковским счетом будет:

BankAccount b1 = new BankAccount(500); // 500 is initial balance parameter
BankAccount b2 = b1; // reference to the same object
b1 = new BankAccount(0);
System.out.println(b1.getBalance() + " " + s2.getBalance()); // prints "0 500"

Так что, если вы думаете об этом таким образом (не то, что делает компилятор, а функционально эквивалентный), сценарий конкатенации строк:

String s1 = "ab";
String s2 = s1;
s1 = new String("abc");
System.out.println(s1 + " " + s2); //prints "abc ab"
10 голосов
/ 30 марта 2012

Действительно, String - это класс, и он назначается / передается по ссылке. Но что сбивает с толку, так это утверждение:

String s = "abc";

Что говорит о том, что String является примитивом (например, int x = 10;); Но это всего лишь ярлык, оператор 'String s = "abc";' фактически компилируется как 'String s = new String( "abc" );' Точно так же, как 'Integer x = 10;' компилируется как 'Integer x = new Integer( 10 );'

Этот механизм называется «боксом».

И еще более запутанно: есть класс 'Integer' и примитив 'int', но String не имеет примитивного эквивалента (хотя char[] подходит близко)

Сийе де Хаан

10 голосов
/ 29 апреля 2011

Не имеет значения, рассматривается ли String как примитив или как объект!

В примере String конкатенация двух строк создает новый экземпляр String , который затем присваивается s1. Переменная s2 по-прежнему ссылается на неизмененный (!) Старый экземпляр String.

Предполагая, что у BankAccount был метод для установки баланса, который возвращает новый BankAccount, ваш пример может выглядеть так:

BankAccount b1 = new BankAccount(500); // 500 is initial balance parameter
BankAccount b2 = b1; // reference to the same object
b1 = b1.createNewAccountWithBalance(0); // create and reference a new object
System.out.println(b1.getBalance() + " " + b2.getBalance()); // prints "0 500"
7 голосов
/ 29 апреля 2011

В Java String объекты назначаются и передаются вокруг по ссылке ; в этом отношении они ведут себя точно так же, как и любой другой объект.

Однако String являются неизменяемыми : нет операции, которая изменяет значение существующей строки без создания нового объекта. Например, это означает, что s1 = s1 + "c" создает новый объект и заменяет ссылку, хранящуюся в s1, ссылкой на этот новый объект.

4 голосов
/ 29 апреля 2011

String является классом, поэтому переменная String является ссылкой.Но это внутренний язык, в том смысле, что у Java есть особая обработка и синтаксис для него, поэтому вы можете делать такие вещи, как ваш пример.

3 голосов
/ 29 апреля 2011

java.lang.String - это объект, а не примитив.

Код, использованный в первом примере:

  1. Определите s1 как "ab"
  2. Установите s2 равным тому же базовому объекту, что и s1
  3. Установите s1 равным новой строке, которая является комбинацией старого значения s1 и "c"

Но для ответаВаш вопрос о ссылке или стоимости, это по ссылке.

1 голос
/ 25 октября 2017

утверждение

если Java обрабатывает строковые переменные как ссылки на любой другой объект, ответ будет "abc abc"

неверно. Java обрабатывает строковые переменные как ссылки на любой другой объект. Строки являются объектами, но ответ «abc ab» тем не менее.

Проблема не в том, что делает оператор присваивания. Оператор присваивания присваивает ссылку на объект String в каждом случае в вашем примере.

Проблема в том, что делает оператор конкатенации ('+'). Создает новый объект String. Как уже говорили другие, это необходимо, потому что объект String является неизменяемым, но это проблема поведения оператора, а не только потому, что String является неизменным. Оператор конкатенации может вернуть новый объект, даже если объект String изменчив.

Напротив, во втором примере b1.setBalance (0) не создает новый объект, он изменяет существующий объект.

0 голосов
/ 16 марта 2016
int s1 = 1;
int s2 = s1; // copies value, not reference
s1 = 42;

System.out.println(s1 + " " + s2); // prints "1 42"

Не печатает "1 42", но "42 1". Принять к сведению каждую отдельную строку. Сначала s1 назначает 1, затем s2 назначает s1, то есть 1 до сих пор (предположим, java не видел третьегоеще нет.) Затем java видит третью строку и немедленно меняет s1 на 42. После этого java сказали распечатать то, что он знает до сих пор, и это s1 равно 42, а s2 равно 1 (старый s1).

Что касается String, происходит то же самое.

String s1 = "ab";
String s2 = s1;
s1 = s1 + "c";
System.out.println(s1 + " " + s2);// prints "abc ab".

Fort String не обязательно меняет s1, а скорее s1 теперь ссылается на новый объект String в памяти кучи, но старый "ab"объект все еще там, с новой ссылкой s2!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...