Строки (String) в Java. Особенности, проблемы, пул строк, создание и работа со строками
- DeveloperNotes »
- Java »
- Строки (String) в Java. Особенности, проблемы, пул строк, создание и работа со строками
Строки в Java — это большая, и не такая уж простая тема. Чтобы разобраться в строках, придется потратить некоторое время. Строки отличаются от обычных объектов в Java и имеют свои особенности. Если вы думаете, что разбираетесь в строках, давайте я задам вам один вопрос.
Что выведет данная программа?
package question;
public class Question {
public static void main(String[] args) {
String s1 = "Something";
String s2 = new String(s1);
if (s1 == s2) System.out.println("s1 == s2");
if (s1.equals(s2)) System.out.println("s1.equals(s2)");
}
}
Не уверены в ответе? Давайте разбираться подробно и к концу данной статьи вы точно будете знать, что тут происходит.
Что такое строка (string) в Java?
В общем и целом, строка - это последовательность символов. Например, весь текст здесь - это и есть строки. Таким образом, массив char'ов в каком-то смысле тоже является строкой. Но в Java для работы со строками определен конкретный класс, который называется String. Он предоставляет ряд методов для работы со строками, которые крайней полезны в работе. Чтобы проиллюстрировать это, давайте приведет массив char'ов к строке и получим длину строки:
char data[] = {'n', 'o', 't', 'e', 's'};
String str = new String(data);
System.out.println( str.length() ); // выведет "5"
Строки не обязательно созадвать с помощью оператора new
. Для их создания можно просто присвоить ссылке на объект (вы же помните, что мы всегда работаем со ссылками, а не с самими объектами?) значение. Кроме того, строки можно соединять с помощью оператора "+" (сложения). Покажем и то и другое на примере:
String a = "abc";
String b = "def";
String c = a + b; // abcdef
В отличие от обычных объектов, которые вы создаете с помощью оператора new
, строки - не мутируемые объекты (immutable objects). То есть, создав строку один раз, вы уже не можете ее изменить. Это значит, что при использовании операций, которые изменяют строку — на самом деле будет создана новая строка. Например, в примере выше мы явно создали строку "c". Но что, если пример выглядел бы следующим образом? Я немного изменил программу для большей понятности.
String a = new String("abc");
String b = new String("def");
a = a + b; // что тут случится?
Ответьте на вопрос: сколько объектов в этой программе? Серьезно, подумайте минуту. Окей, я считаю, что у нас тут три объекта, а не два, как можно было бы подумать. Если строки не мутируемы, значит, что когда мы сложили две строки - фактически JVM создала третий объект (но явно мы этого не видим), после чего ссылка "a" была "переведена" на этот созданный объект. А первоначальная ссылка "a" на объект "abc" была потеряна.
Почему это вообще важно? Представьте, что вам нужно обработать 100.000 строк (например, разобрать по частям какую-нибудь книгу или большую базу данных). Если вы будете каждый раз соединять строки таким образом, то вы создадите в программе огромное количество объектов. Всё это будет работать медленно. Поэтому, если вам нужно много изменять строку, лучше использовать StringBuffer или StringBuilder (я про них еще не писал, поищите информацию в интернете, если интересно).
Последнее, что хотелось бы заметить: класс String представляет последовательность символов в формате кодировки UTF-16
, которая поддерживает множество языков. И это очень круто!
Я рекомендую хотя бы пролистать официальную документацию по строкам от Oracle, чтобы узнать, какие методы и возможности поддерживает класс String.
Что такое пул строк (string pool) в Java и зачем он нужен?
Пул строк (string pool) в Java, как понятно из описания, это некий пул (или список) объектов класса String, который хранится в специальном месте кучи (Java Heap). Разработчики Java сделали так, чтобы оптимизировать выделение памяти и хранение строк, ускорить и оптимизировать работу с ними.
Пул строк был создан по той простой причине, что строки - это самое используемое в программах на Java. Мы как минимум очень часто, а как максимум - почти всегда работает со строками в программах.
Пул строк работает следующим образом: когда мы создаем строку с помощью конструкции
String str = "HELLO";
Эта строка попадает в пул строк. Когда мы создаем другую строку с тем же значением:
String str2 = "HELLO";
То на самом деле сначала происходит поиск по пулу строк. И если там уже найдена такая строка - то str2 присваивается ссылка на уже созданный объект (на который указывает и str).
По этой причине следующая конструкция выведет true
(вы же не забыли, что мы работаем не с самими объектами, а со ссылками на них?):
String str1 = "abc";
String str2 = "abc";
System.out.println(str1 == str2);
Тут может показаться, что мы создаем другой объект строки, но на самом деле это не так - происходит поиск по пулу строк.
Создание строки как нового объекта
Механизм, описанный выше - классный. Он позволяет программисту меньше писать, а JVM использовать меньше памяти и быстрее работать. Но на самом деле мы можем создать объект строки явно, даже в случае, если такая строка уже была создана и записана в пул строк:
String str = new String("HELLO");
В этом случае объект будет создан, причем будет создан в куче. Таким образом следующий код:
String a = new String("abc");
String b = new String("abc");
System.out.println (a == b);
выдаст нам false
, ведь ссылки указывают на разные объекты. Поиск по пулу строк тут не происходит.
Всё происходящее отлично иллюстрируется следующим изображением, которое я нашел в интернете (кто я такой, чтобы что-то рисовать, хаха):
Метод intern() класса String
При создании объекта для новой строки через оператор new
мы можем также попросить JVM поискать эту строку в пуле строк с помощью метода intern(), следующим образом:
String a = new String("abc").intern();
В данном случае, если у нас уже есть такая строка в пуле строк, то будет возвращена ссылка на строку из пула строк, и новый объект создан не будет.
Думаю, теперь вы можете ответить на вопрос из начала этой статьи: будет выведено только s1.equals(s2)
. Потому, что мы не обратились к пулу строк при сздании строки s2
, даже несмотря на то, что ее значение взято из s1.
Вопросы пишите в комментарии. Удачи!
Комментарии