Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Как String хранится в памяти
Особенность String: Immutable (неизменяемость)
String в Java — это **immutable** (неизменяемый) объект. Это одна из самых важных особенностей, которая влияет на то, как String хранится в памяти.
Внутренняя структура String
Java 8 и ранее
public final class String {
private final char[] value; // Массив символов
private final int offset; // Смещение в массиве
private final int count; // Количество символов
private int hash; // Кэшированный хэш
public String(String original) {
this.value = original.value;
this.offset = original.offset;
this.count = original.count;
this.hash = original.hash;
}
}
Java 9 и позже (Compact Strings)
С Java 9 введена оптимизация Compact Strings:
public final class String {
// Вместо char[] используется byte[]
private final byte[] value; // Один или два байта на символ
private final byte coder; // LATIN1 (1 байт) или UTF16 (2 байта)
private int hash; // Кэшированный хэш
}
Где хранится String в памяти
String Pool (Пул строк)
Все строк-литералы хранятся в специальной памяти — String Pool (в Java 8 в пермgen, с Java 8+ в heap):
public class StringMemoryExample {
public static void main(String[] args) {
// Пример 1: String literal → String Pool
String s1 = "Hello"; // Создаётся в String Pool
String s2 = "Hello"; // Ссылается на ту же строку в Pool
System.out.println(s1 == s2); // true (один объект)
System.out.println(s1.equals(s2)); // true
// Пример 2: String с new → Heap
String s3 = new String("Hello"); // Новый объект на heap
String s4 = new String("Hello"); // Ещё один новый объект
System.out.println(s3 == s4); // false (разные объекты)
System.out.println(s3.equals(s4)); // true (одинаковое содержимое)
// Пример 3: intern() — добавить в Pool
String s5 = new String("Hello").intern(); // Добавляется в Pool
System.out.println(s1 == s5); // true (теперь один объект)
}
}
Визуализация памяти
┌─────────────────────────────────────┐
│ STRING POOL (в Heap, Java 8+) │
│ │
│ ┌──────────────────────────────┐ │
│ │ "Hello" (byte[] или char[]) │◄─┼─── s1, s2, s5 указывают сюда
│ └──────────────────────────────┘ │
│ │
│ ┌──────────────────────────────┐ │
│ │ "World" (byte[] или char[]) │ │
│ └──────────────────────────────┘ │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ HEAP (остальные объекты) │
│ │
│ s3 → ┌──────────────────────────┐ │
│ │ "Hello" (отдельный) │ │
│ └──────────────────────────┘ │
│ │
│ s4 → ┌──────────────────────────┐ │
│ │ "Hello" (отдельный) │ │
│ └──────────────────────────┘ │
└─────────────────────────────────────┘
Механизм String Interning
Автоматический Interning (String Literals)
String s1 = "Java"; // Автоматически добавляется в Pool
String s2 = "Java"; // Используется из Pool
String s3 = "Ja" + "va"; // Компилятор оптимизирует → компилирует как "Java"
String s4 = "Ja";
String s5 = s4 + "va"; // Runtime конкатенация, НЕ в Pool
Явный Interning
String s1 = new String("Hello");
String s2 = s1.intern(); // Добавляет s1 в String Pool и возвращает ссылку
String s3 = "Hello";
System.out.println(s2 == s3); // true (оба из Pool)
Immutability и его следствия
Почему String immutable
public class StringImmutability {
// 1. Security: пароли, ключи хранятся в String
String password = "secret123";
// Нельзя изменить → безопаснее
// 2. String Pool работает
// Если бы String было изменяемым, Pool развалилась бы
String s1 = "Hello";
String s2 = "Hello"; // указывает на то же место
// s1.changeCharAt(0, 'J'); // Если бы было возможно, s2 тоже изменится!
// 3. Thread safety
// Immutable объекты безопасны для многопоточности
// Не нужна синхронизация
}
Операции с String (создают новые объекты)
String s = "Hello";
// Каждая операция создаёт НОВЫЙ String
String s1 = s.toUpperCase(); // "HELLO" → новый объект
String s2 = s.substring(1); // "ello" → новый объект
String s3 = s.replace('l', 'L'); // "HeLLo" → новый объект
String s4 = s.concat(" World"); // "Hello World" → новый объект
// Исходный s остаётся "Hello"
Оптимизация String (StringBuilder/StringBuffer)
Проблема: неэффективная конкатенация
String result = "";
for (int i = 0; i < 1000; i++) {
result += "item" + i; // ❌ Создаёт 1000+ новых String объектов!
}
// Это очень неэффективно для памяти и производительности
Решение: StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append("item").append(i); // ✅ Эффективно
}
String result = sb.toString(); // Один новый String
// Различие:
// - String (immutable): безопасен, медленен при конкатенации
// - StringBuilder (mutable): быстрый, НЕ потокобезопасен
// - StringBuffer (mutable): быстрый, потокобезопасен (синхронизирован)
Compact Strings в Java 9+
public class CompactStrings {
// До Java 9: каждый символ = 2 байта (char)
// Строка "Hello" = 10 байт (5 символов × 2 байта)
// С Java 9: если все символы < 256 (LATIN1)
// Строка "Hello" = 5 байт (1 байт на символ)
// Строка "Привет" = 12 байт (UTF16, 2 байта на символ)
// Автоматическое переключение между LATIN1 и UTF16
byte coder; // 0 = LATIN1, 1 = UTF16
}
Практические советы
public class StringBestPractices {
// 1. Используй StringBuilder для конкатенации в цикле
// ❌ String result = ""; for (i) result += ...;
// ✅ StringBuilder sb = new StringBuilder(); for (i) sb.append(...);
// 2. Используй == для сравнения литералов в switch
switch (status) {
case "active":
break; // ✅ Быстро (String Pool)
}
// 3. Будь осторожен с intern() в продакшене
// Может привести к утечкам памяти, если добавлять много строк
// 4. Помни о String Pool при работе с большим числом уникальных строк
// У String Pool конечный размер и оно может переполниться
}
Вывод
String в Java хранится:
- String literals → в String Pool (heap, Java 8+)
- String объекты с new → в обычной heap памяти
- Внутренне: массив char[] (Java 8) или byte[] (Java 9+)
- Immutable: не может быть изменён после создания
- Оптимизирован: с Java 9 используется Compact Strings для экономии памяти