Страницы

Поиск по вопросам

среда, 27 ноября 2019 г.

Передача по значению в Java

#java


Добрый день. Читал про вызов по значению и натолкнулся на два примера. 1-ый:

public class Application {
    public static void main(String[] args) {
        String[] x = {"A"};
        String[] y = x;
        x[0] = "B";
        System.out.print(x[0] + " " + y[0]);
    }
}


Тут вроде бы все понятно. Ссылка на строковый массив "y" будет совпадать со ссылкой
на массив "x"и произойдет копирование и ответом будет "B B". Но вот второй пример:

public class Application {
    public static void main(String[] args) {
        String x = "A";
        String y = x;
        x = "B";
        System.out.print(x + " " + y);
    }
}


Здесь почему то ответ "B A", хотя я думал что правильный ответ будет "B B". Ход рассуждений
был такой же как и в первом примере. Подскажите пожалуйста, что за подвох в этом примере
? Ведь String - это класс, а не тип в Java и в обоих примерах мы создаем экземпляр
класса String.
    


Ответы

Ответ 1



В первом случае у вас есть массив (обозначим его M, хотя в Java вы не можете обратиться к нему иначе, как через ссылку). Нулевой элемент массива M указывает сначала на строку "A", затем на строку "B". И x, и y, заметьте, ссылаются на один и тот же массив M. Когда вы меняете данные в массиве через любую из ссылок, вы меняете одни и те же данные. Во втором случае у нас есть переменные x и y, которые ссылаются сначала на одну и ту же строку "A", а затем x начинает ссылаться на другую строку ("B"). Всё просто. Вот вам аналогия. В первом случае у вас есть клетка. И вы, и я смотрим на эту клетку. В клетке сначала сидел белый кролик, а потом туда посадили чёрного кролика. Теперь и вы, и я смотрим на клетку с чёрным кроликом. Во втором случае клетки нет, я смотрю на белого кролика, вы смотрите на того же кролика, что и я, а потом я отвернулся и стал смотреть на чёрного кролика. Ну да, теперь мы смотрим на разных кроликов. Теперь замените кроликов на строки, клетку на массив, «смотреть» на «иметь ссылку». Вы не должны искать универсальных простых правил типа «если я меняю вот эту штуку, та тоже поменяется». Или «не поменяется». Или «поменяется, если уровень косвенности больше 1». Рассуждайте о смысле операций каждый раз. Не удержался, добавил картинки, о которых говорил @void. Смотрите. Первый пример: String[] x = {"A"}; String[] y = x; x[0] = "B"; Второй пример: String x = "A"; String y = x; x = "B"; Так понятнее?

Ответ 2



В первом случае у вас есть 2 ссылки на один и тот же массив. String[] x = {"A"}; //x указывает на массив {"A"} (x[0] == "A") String[] y = x; //x и y указывают на массив {"A"} (x == y; x[0] == y[0]; x[0] == "A"; y[0] == "A") x[0] = "B"; //в массиве {"A"} строка с индекcом 0 поменялась на строку "B", изменилось состояние массива и теперь это массив {"B"}. Но это все еще тот же самый объект (x == y; x[0] == y[0]; x[0] == "B"; y[0] == "B") Во втором же случае у вас две разных ссылки на экземпляры класса String: String x = "A"; //x указывает на строку "A" String y = x; //x и y указывают на строку "A" (x == y) String x = "B" //x указывает на строку "B", y указывает на строку "A" (x != y)

Ответ 3



Никак невозможно изменить содержимое созданной строки, по крайней мере в безопасном (safe) коде и без рефлексии. Поэтому вы при изменении строк изменяете не сами строки, а значения переменных, указывающих на строки. Например, код s = s.Replace ("foo", "bar"); не изменяет содержимое строки s, которое было до вызова метода Replace — он просто переназначает переменную s на новообразованную строку, которая является копией старой за исключением всех подстрок «foo», заменённых на «bar».

Комментариев нет:

Отправить комментарий