Почему объект String не передаётся по ссылке

251
10 ноября 2017, 07:31

Доброго времени суток.
В консоль данный код выводит: "slipstream slip stream", а не "slipstream slipstream stream" как я предполагал. Помогите разобраться, почему s1 после fix(String s1) не изменила значения на "slipstream". Спасибо. ссылка

class PassS
{
    public static void main(String [] args)
    {
        PassS p = new PassS();
        p.start();
    }
    void start()
    {
        String s1 = "slip";
        String s2 = fix(s1);
        System.out.println(s1 + " " + s2);
    }
    String fix(String s1)
    {
        s1 = s1 + "stream";
        System.out.print(s1 + " ");
        return "stream";
    }
}
Answer 1

Читаем доки.

Strings are constant; their values cannot be changed after they are created.

Строки иммутабельны; их значение нельзя поменять после создания.

s1 = s1 + "stream" в методе fix меняет лишь локальную переменную на стеке. Оригинальная строка, определённая в методе start, не меняется.

Answer 2

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

Вот пример с демонстрацией передачи объекта по значению:

class Ideone
{
    String message;     
    Ideone(String message) { this.message = message; } 
    public static void foo (Ideone obj) 
    {
        obj = new Ideone("Если бы я был передан по ссылке, вы бы увидели это сообщение.");
    }
    public static void main (String[] args) throws java.lang.Exception
    {
        Ideone obj = new Ideone("Но вы увидите вот это, потому что параметры в Java передаются по значению.");
        foo(obj);
        System.out.println(obj.message);
    }
}

Запустить пример онлайн можно тут: https://ideone.com/0upGqO

Answer 3

Если вам необходимо изменять строку, используйте StringBuilder.

Answer 4

Все просто! Вы создали переменную String s1 = "slip"; в методе start() и передали ее как параметр в метода fix(String s1) и в этот момент в стеке метода создалась новая переменная s1, таким образом у нас две переменные (одна вне метода fix, другая, локальная в методе fix), которые ссылаются на один объект строки. В методе fix Вы затем локальной переменной s1 присвоили ссылку на новый объект строки, в то время как переменная s1 метода start() по-прежнему ссылается на объект строки"slip".

P.S. Всем, кто утверждает, что в Java все параметры передаются по значению. Так оно и есть! Важно понимать, что при передаче объекта передается копия ссылки на объект. Поэтому можно менять свойство объекта, но ни сам объект. Если бы передача была бы по ссылке, то присвоение переменной метода нового объекта отобразилась бы на всех внешних переменных, которые бы стали бы ссылаться на новый объект. Спасибо всем, кто меня поправил! Ссылка(см. Passing Reference Data Type Arguments)

Answer 5

Вы все правильно понимаете в теории ссылочных типов и примитивов. Действительно в данном случае, исходя из общей концепции, ваша переменная должна была изменить свое значение. Вся проблема в том, что класс String объявлен как final. Про подробности использования этого ключевго слова вы можете почитать сами, но суть в том, что не, во -первых, унаследоваться от таких классов нельзя. Во -вторых, в данном случае это самое главное, вы не можете изменить ссылку на созданный объект. Т.е. каждый раз, присваивая одной и той же переменной новое значение на самом деле вы не изменяете старый объект, а создаете новый. Именно это свойство не позволяет Вам видеть передачи значения по ссылке в данном коде, ведь по сути объект типа стринг не изменился, а создался заново. Причины того, что string объявлен как final, достаточно много, основные из них состоят в обеспечении потокобезопасности, скорости работы, соблюдение требований безопасности в целом(это не позволит подменить стринг классом наследником и производить с ним какие-либо манипуляции). В целом же идею ссылочных типов и примитивов , как я уже говорил, вы поняли правильно. Чтобы убедиться в этом , поэксперементируйте с классами, не объявленными как final. Например, в качестве эксперемента, предлагаю взять ArrayList. Дополните свой код таким образом, и увидите. что передача по ссылке действительно отрабатывает...

import java.util.ArrayList;
class PassS {
    public static void main(String[] args) {
        PassS p = new PassS();
        ArrayList <String> list = new ArrayList<>();
        list.add("one");
        list.add("two");
        list.add("three");
        System.out.println(list);
        delFirstElement(list);
        System.out.println(list);
        p.start();
    }
    void start() {
        String s1 = "slip";
        String s2 = fix(s1);
        System.out.println(s1 + " " + s2);
    }
    String fix(String s1) {
        s1 = s1 + "stream";
        System.out.println(s1 + " ");
        return "stream";
    }
    static void delFirstElement (ArrayList list){
        list.remove(0);
    }
}
READ ALSO
Как сделать поиск по нескольким полям таблицы

Как сделать поиск по нескольким полям таблицы

на данный момент поиск работает отдельно по каждому полю (для каждого поля создан свой сервлет, и страница jsp для вывода данных) с помощью...

230
Как правильно использовать Fork/Join Framework в Java?

Как правильно использовать Fork/Join Framework в Java?

I write simple program with Fork/Join FrameworkFor first version of my program, that not working correct, I used the book "Herbert Shield

219
Работа с GET/POST и брузером

Работа с GET/POST и брузером

Нужно реализовать такой функционал для входа в приложение через twitchПользователь в приложении (написанном на JavaFx) нажимает кнопку Login, открывается...

197