Розуміння ініціалізації рядків в Java

Ви колись замислювалися над різними способами ініціалізації рядка в Java? Ви використовуєте літерали рядка (наприклад, String str = "abc") чи застосовуєте ключове слово new, як це: String str = new String("abc")? На перший погляд, здається, що обидва підходи досягають одного й того ж результату — створення нового рядка. Однак спосіб управління пам'яттю за лаштунками має велике значення.

pic

Зліва: Літерали рядка, як-от "abc" і "xyz", зберігаються в пулі рядків. Справа: Коли новий рядок створюється з використанням new, він додається ще в одну копію в купу поза пулом рядків.

Літерали Рядків

Коли ви використовуєте літерали рядків, як-от String str = "abc", значення рядка "abc" додається до Пулу рядків (особлива область в пам'яті купи, резервована для зберігання літералів рядків). Змінна str потім вказує на цей пулований рядок. Якщо рядок "abc" вже існує в Пулі рядків, str буде вказувати на існуючий рядок замість того, щоб створювати новий. Якщо пізніше ви присвоїте str інше значення, наприклад, "xyz", новий рядок "xyz" також додається до пулу рядків (якщо його там ще немає), і тепер str вказує на нього.

Рядки з використанням ключового слова new

Використання ключового слова new, наприклад, String str = new String("abc"), створює новий об'єкт у пам'яті купи щоразу. Навіть якщо вміст рядка той самий, буде створено новий об'єкт. Додатково:

  • Цей новий об'єкт посилається на значення рядка з пулу рядків, якщо воно вже існує.
  • Якщо рядок ще не існує в Пулі рядків, він також буде доданий туди.

Ця поведінка може призвести до більшого споживання пам'яті, оскільки кожен виклик з ключовим словом new виділяє пам'ять для нового об'єкта, навіть якщо рядок вже існує в Пулі рядків.

Незмінність Рядків

Рядки в Java є незмінними, що означає, що після створення рядка його значення не можна змінити. Наприклад:

  • Коли ви переопризначаєте str на нове значення, наприклад str = "xyz", новий рядок створюється в Пулі рядків (якщо його там ще немає), і тепер str вказує на новий рядок.
  • Оригінальний рядок залишається незмінним, хоча з часом він може бути зібраний сміттям, якщо на нього більше немає посилань.

Інтернування Рядків

Ви можете явно додавати рядки до Пулу рядків, використовуючи метод intern(). Наприклад:

String str = new String("abc");  
String internedStr = str.intern();

Тут internedStr буде вказувати на пулований варіант рядка, забезпечуючи існування лише одного екземпляра цього рядка в Пулі рядків.

Наслідки для Продуктивності

Використання літералів рядків зазвичай є більш ефективним у плані пам'яті, оскільки Пул рядків запобігає дублюванню однакових рядків. Ключове слово new завжди створює новий об'єкт в пам'яті купи, незалежно від того, чи існує вже цей рядок у Пулі рядків. Надмірне використання new String(...) може призвести до зайвого виділення пам'яті та перевантаження збору сміття.

Ключові моменти

  1. Літерали рядків працюють швидше і є більш ефективними з точки зору пам'яті, ніж використання ключового слова new. Тому використовуйте літерали, коли це можливо.
  2. Будьте обережні щодо впливу на пам'ять при створенні кількох об'єктів рядків без потреби.
  3. Використовуйте intern(), щоб переконатися, що рядки потрапляють у пул, коли це необхідно, особливо у випадках, коли є багато дубльованих рядків.

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

Перекладено з: Understanding String Initialization in Java

Leave a Reply

Your email address will not be published. Required fields are marked *