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

В чем разница между инициализацией String через new String и через " "?

1.2 Junior🔥 181 комментариев
#JVM и управление памятью#Основы Java

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

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

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

# Разница между инициализацией String через new String() и через литерал ""

Основное различие

В Java есть два способа создания String объектов: через литерал (нативный синтаксис) и через конструктор new String(). Эти подходы создают строки в разных местах памяти и имеют различные последствия для производительности и поведения.

1. String литерал ("hello")

Когда вы создаете строку через литерал, Java помещает ее в специальную область памяти под названием String Pool (String Intern Pool).

String str1 = "hello";
String str2 = "hello";
String str3 = "hello";

// Все три переменные указывают на один и тот же объект в String Pool
System.out.println(str1 == str2); // true (один объект в памяти)
System.out.println(str1.equals(str2)); // true

Характеристики:

  • Строка помещается в String Pool (heap memory)
  • Если строка уже существует в pool, создается новая ссылка на существующий объект
  • Экономия памяти благодаря дедупликации
  • Очень быстрое сравнение через == (сравнение ссылок)

2. Создание через конструктор new String()

Когда вы используете конструктор new String(), Java ВСЕГДА создает новый объект в heap памяти, даже если такая строка уже существует в String Pool.

String str1 = new String("hello");
String str2 = new String("hello");
String str3 = "hello";

// str1 и str2 - разные объекты в heap
// str3 - объект в String Pool
System.out.println(str1 == str2); // false (разные объекты)
System.out.println(str1.equals(str2)); // true (одинаковое содержимое)
System.out.println(str1 == str3); // false (разные объекты)

Характеристики:

  • Создается новый объект в обычной heap памяти
  • String Pool все равно заполняется для литерала
  • Больше потребления памяти
  • Сравнение через == будет false

Визуальная демонстрация в памяти

Литерал (""):
┌─────────────────────┐
│   String Pool       │
├─────────────────────┤
│  "hello" @2548      │ ← str1, str2, str3 указывают сюда
└─────────────────────┘

Конструктор new String():
┌──────────────────────┐         ┌──────────────────────┐
│   Обычная heap       │         │   String Pool        │
├──────────────────────┤         ├──────────────────────┤
│ "hello" @1234        │         │ "hello" @2548        │
│ "hello" @5678        │         └──────────────────────┘
└──────────────────────┘
str1 @1234, str2 @5678 указывают на heap

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

Пример 1: Сравнение через ==

String s1 = "hello";           // String Pool
String s2 = "hello";           // String Pool (тот же объект)
String s3 = new String("hello"); // Heap
String s4 = new String("hello"); // Heap (новый объект)

// Сравнение ссылок (==)
System.out.println(s1 == s2);  // true - один объект
System.out.println(s1 == s3);  // false - разные объекты
System.out.println(s3 == s4);  // false - разные объекты

// Сравнение значений (equals)
System.out.println(s1.equals(s3)); // true - одинаковое содержимое
System.out.println(s3.equals(s4)); // true - одинаковое содержимое

Пример 2: Использование concat() и new String()

String result1 = "Hello" + " World"; // Результат в String Pool
String result2 = new String("Hello" + " World"); // Новый объект в Heap

System.out.println(result1 == result2); // false

Пример 3: String.intern()

Метод intern() добавляет строку в String Pool (или возвращает ссылку на существующую).

String s1 = new String("hello");
String s2 = "hello";

System.out.println(s1 == s2); // false

// Добавляем s1 в String Pool
String s3 = s1.intern();
System.out.println(s3 == s2); // true (обе указывают на pool)

Таблица сравнения

АспектЛитерал ""new String()
РазмещениеString PoolHeap
ПереиспользованиеДа (дедупликация)Нет
Потребление памятиМинимальноеБольше
ПроизводительностьБыстрееМедленнее
Сравнение == работаетДаНет
Создание при каждом вызовеНетДа

Какой способ использовать?

Используйте литерал "" когда:

// 1. Обычное объявление строковых констант
String error = "File not found";
String apiUrl = "https://api.example.com";

// 2. Вам нужна экономия памяти
for (int i = 0; i < 1000; i++) {
    String msg = "Processing item"; // Использует одну строку из pool
}

// 3. Вы сравниваете строки через ==
if (status == "ACTIVE") { // Работает только с литералами
    // ...
}

Используйте new String() когда:

// 1. Нужна новая копия строки (очень редко)
char[] data = "secret".toCharArray();
String secret = new String(data);
// Теперь можно очистить массив, оригинальная строка не затрагивается
Arrays.fill(data, ' ');

// 2. Нужно конвертировать массив байт
byte[] bytes = "Hello".getBytes();
String str = new String(bytes, StandardCharsets.UTF_8);

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

Тест на большом количестве строк

// Создание 100,000 одинаковых строк
long start = System.nanoTime();

for (int i = 0; i < 100_000; i++) {
    String str = "test"; // Все указывают на один объект в pool
}

long literalTime = System.nanoTime() - start;

start = System.nanoTime();

for (int i = 0; i < 100_000; i++) {
    String str = new String("test"); // 100,000 разных объектов
}

long newStringTime = System.nanoTime() - start;

System.out.println("Literal: " + literalTime);
System.out.println("new String: " + newStringTime);
// new String() будет медленнее и потребит больше памяти

Правильное сравнение String

// ❌ Неправильно - зависит от того, как была создана строка
if (str1 == str2) {
    // Может работать или не работать
}

// ✅ Правильно - всегда безопасно
if (str1.equals(str2)) {
    // Гарантированно сравнивает содержимое
}

// ✅ Для игнорирования регистра
if (str1.equalsIgnoreCase(str2)) {
    // Сравнивает без учета регистра
}

Выводы

  1. Используйте литералы ("") как основной способ создания строк - это экономит память и улучшает производительность
  2. Используйте new String() очень редко - только для специальных случаев (работа с байтами, особые требования к изоляции)
  3. Сравнивайте строки через equals(), а не через ==
  4. String Pool - это автоматическая оптимизация, которая экономит память за счет дедупликации строк
  5. JVM автоматически управляет String Pool, поэтому не нужно вызывать intern() в обычном коде