← Назад к вопросам

Что Java вернет, если создать строку, которая уже есть в String Pool

1.3 Junior🔥 71 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что Java вернет, если создать строку, которая уже есть в String Pool

Ответ: Java вернёт ссылку на существующий объект String в String Pool, а не создаст новый объект. Это называется string interning.

Как работает String Pool

String Pool — это специальная область памяти в JVM, где хранятся уникальные строковые значения. Это одна из важных оптимизаций JVM.

// Обе переменные указывают на ОДИН и ТОТ ЖЕ объект
String str1 = "Hello";
String str2 = "Hello";

System.out.println(str1 == str2); // true! (Одна и та же ссылка)
System.out.println(str1.equals(str2)); // true (Одинаковое значение)

Создание с новым оператором

Когда используешь new, Java создаёт новый объект в heap, даже если строка есть в пуле:

String str1 = "Hello"; // В String Pool
String str2 = new String("Hello"); // Новый объект в heap

System.out.println(str1 == str2); // false! (Разные объекты)
System.out.println(str1.equals(str2)); // true (Одинаковое значение)

Явное добавление в пул с intern()

String str1 = "Hello";
String str2 = new String("Hello");

System.out.println(str1 == str2); // false

// Добавляем str2 в пул
String str3 = str2.intern();

System.out.println(str1 == str3); // true! (Теперь указывают на один объект)

Когда строки автоматически добавляются в пул

1. String literals (литералы):

String s1 = "Java"; // Автоматически в пул

2. Конкатенация с компиляции:

String s1 = "Hello" + "World"; // "HelloWorld" в пул

3. Методы, возвращающие intern'ированные строки:

String s = "hello".toUpperCase(); // Если результат известен на компиляции

Когда НЕ добавляются в пул

1. Создание с new:

String s = new String("test"); // В heap, не в пул

2. Конкатенация с переменными:

String a = "Hello";
String b = "World";
String c = a + b; // НЕ в пул, в heap
System.out.println(c == "HelloWorld"); // false

3. Результаты методов:

String s1 = "hello";
String s2 = s1.substring(0, 3); // НЕ в пул
System.out.println(s2 == "hel"); // false

Практический пример

public class StringPoolExample {
    public static void main(String[] args) {
        // Сценарий 1: Литералы
        String a = "Java";
        String b = "Java";
        System.out.println(a == b); // true (Один объект в пуле)
        
        // Сценарий 2: new оператор
        String c = new String("Java");
        System.out.println(a == c); // false (c в heap)
        
        // Сценарий 3: intern()
        String d = c.intern();
        System.out.println(a == d); // true (d теперь указывает на объект в пуле)
        
        // Сценарий 4: Конкатенация с переменными
        String e = "Ja";
        String f = "va";
        String g = e + f; // НЕ в пуле
        String h = "Java";
        System.out.println(g == h); // false
        System.out.println(g.equals(h)); // true
    }
}

Почему это важно

Экономия памяти:

  • String Pool экономит память благодаря переиспользованию одинаковых строк
  • Если приложение использует много одинаковых строк, пул существенно экономит память

Производительность сравнения:

  • == с intern'ированными строками работает в O(1) (сравнение ссылок)
  • Без interning нужно equals(), это O(n) (посимвольное сравнение)
// Плохо: сравниваешь строки в heap
String str1 = new String("test");
String str2 = new String("test");
if (str1 == str2) { } // false, хотя значения одинаковые

// Хорошо: используешь equals
if (str1.equals(str2)) { } // true

Потенциальные проблемы

1. Утечка памяти при частом intern():

// Плохо: каждая новая строка добавляется в пул
for (int i = 0; i < 1000000; i++) {
    String s = ("Key_" + i).intern(); // Пул растёт!
}
// String Pool может переполниться

2. Ложное ощущение оптимизации:

String s1 = new String("long string");
String s2 = s1.intern(); // Может быть медленнее, чем пользу даёт

Контроль размера String Pool

# JVM параметры для настройки пула строк
# -XX:StringTableSize=<число> (по умолчанию 60013 для Java 8)

java -XX:StringTableSize=1000000 MyApplication

Best Practices

1. Используй == только с уверенностью в intern'ировании:

// ✅ Правильно: оба литерала
if ("Hello" == "Hello") { }

// ❌ Неправильно: переменная может быть не в пуле
String userInput = getUserInput();
if (userInput == "expected") { } // Опасно!

// ✅ Правильно: используй equals
if (userInput.equals("expected")) { }

2. Не полагайся на interning для оптимизации:

// ❌ Избегай
String key = ("user_" + userId).intern();

// ✅ Лучше
String key = "user_" + userId; // Компилятор сам позаботится

3. Явный intern() только в специальных случаях:

// Имеет смысл, только если строка часто сравнивается по ==
String s1 = receivedFromNetwork().intern();
if (s1 == "KnownValue") { }

Заключение

Java вернёт ссылку на существующий объект в String Pool, если строка уже там есть. Это происходит автоматически для литералов и результатов некоторых операций, но не для строк, созданных через new. Для явного добавления в пул используй .intern(), но будь осторожен с утечками памяти при частом применении.

Что Java вернет, если создать строку, которая уже есть в String Pool | PrepBro