Як слід копіювати рядки на Java?


199
    String s = "hello";
    String backup_of_s = s;
    s = "bye";

На даний момент змінна резервного копіювання все ще містить вихідне значення "привіт" (це через незмінність права String?).

Але чи справді безпечно копіювати рядки цим методом (що, звичайно, не є безпечним для копіювання звичайних змінних об'єктів), або краще це написати? :

    String s = "hello";
    String backup_of_s = new String(s);
    s = "bye";

Іншими словами, яка різниця (якщо така є) між цими двома фрагментами?


EDIT - причина безпеки першого фрагмента:

Дозвольте мені пояснити речі трохи детальніше, грунтуючись на вже наданих хороших відповідях (які по суті були зосереджені на питанні про різницю продуктивності між двома фрагментами:

Струни незмінні в Java, це означає, що об'єкт String не може бути змінений після його побудови. Отже,

String s = "hello";створює новий екземпляр String і присвоює йому адресу s( sє посиланням на екземпляр / об'єкт)

String backup_of_s = s;створює нову змінну backup_of_sта ініціалізує її, щоб вона посилалась на об'єкт, на який посилається даний момент s.

Примітка. Незмінність рядків гарантує, що цей об'єкт не буде змінено: наша резервна копія в безпеці

Примітка 2: Механізм збору сміття Java гарантує, що цей об’єкт не буде знищений до тих пір, поки на нього посилається хоча б одна змінна ( backup_of_sу цьому випадку)

Нарешті, s = "bye";створює ще один екземпляр String (через незмінність - це єдиний спосіб) та змінює sзмінну, щоб вона тепер посилалась на новий об’єкт.

Відповіді:


141

Оскільки рядки незмінні, обидві версії є безпечними. Останній, однак, є менш ефективним (він створює додатковий об’єкт і в деяких випадках копіює символьні дані).

Зважаючи на це, слід віддати перевагу першій версії.


15
Незмінюваність тут нічого спільного. Це просто те, як працюють посилання на об'єкти. Я можу надати еквівалентний приклад StringBuilder.
GriffeyDog

1
@BalusC, я не бачу, як новий String () міг би створити що-небудь у пулу String JVM. Лише рядкові літерали та ті, що передаються в пул через intern (), є у пулі.
Snicolas

3
@GriffeyDog: Я читаю питання менш буквально. Що я говорю, це те, що можна безпечно видавати посилання на об'єкт рядка, не боячись, що хтось може змінити рядок.
NPE

2
@GriffeyDog Я вважаю ваш коментар дуже оманливим: незмінність - це те, що робить перший фрагмент безпечним, чому б ви сказали, що він не має нічого спільного з "це"?
Себастьян

5
@Sebastien Все, що він робить, - це переназначення контрольної змінної sдля позначення іншого об'єкта ( String"бай"). Це не впливає на те, на що посилається змінна backup_of_sпосилання ( String"привіт"). Як я вже сказав, я міг би надати еквівалентний приклад з StringBuilders, які не є незмінними. Мій коментар в основному стосується твердження ОП: На даний момент змінна резервного копіювання все ще містить початкове значення "привіт" (це через право незмінності String?).
GriffeyDog

22

Рядки - це незмінні об'єкти, тому їх можна скопіювати, просто скопіювавши посилання на них, тому що об'єкт, на який посилається, не може змінитися ...

Таким чином, ви можете без проблем копіювати, як у своєму першому прикладі:

String s = "hello";
String backup_of_s = s;
s = "bye";

10

Ваша друга версія менш ефективна, оскільки створює додатковий об'єкт рядка, коли просто немає необхідності в цьому.

Незмінюваність означає, що ваша перша версія поводиться так, як ви очікуєте, і, таким чином, є перевагою підходу.


0

Другий випадок також неефективний з точки зору пулу String, вам потрібно явно зателефонувати intern () при поверненні, щоб зробити його інтерном.


-16
String str1="this is a string";
String str2=str1.clone();

Як щодо такої копії? Я думаю, що краще отримати нову копію, щоб дані str1не впливали, коли str2вони посилаються та змінювались у подальшій дії.


3
Stringнезмінна. клонування Strings не має особливого сенсу.
Володимир
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.