Карта / Синтаксис и типы / String — текст

String — текст

String — это текст в двойных кавычках: "Артур". Внутри — цепочка символов, у каждого свой номер (индекс), считаем с нуля.

А0 р1 т2 у3 р4
"Артур".length() → 5 · .charAt(0) → 'А' · .substring(1,3) → "рт"

Две ловушки на старте

1. Строки неизменяемы. Любой метод не меняет строку, а возвращает новую. Поэтому результат надо присвоить:

String s = "hi";
s.toUpperCase();      // ❌ результат потерян — s всё ещё "hi"
s = s.toUpperCase();  // ✅ теперь s = "HI"

2. Сравнивай через equals, а не ==. equals сравнивает содержимое, == — ссылки (один ли это объект).

name.equals("Артур")  // ✅ сравнить текст
name == "Артур"       // ❌ так нельзя

Частые методы

МетодЧто делаетРезультат
s.length()длинаint
s.toUpperCase()в верхний регистрString
s.charAt(0)символ по индексуchar
s.substring(1, 3)вырезать частьString
s.contains("рт")содержит лиboolean
s.equals("...")сравнить текстboolean
s.trim()убрать пробелы по краямString
Копнуть глубже

Почему строки вообще нельзя менять? Четыре причины:

  • Безопасность. Строки — это пути к файлам, URL, параметры подключения. Будь они изменяемы, значение можно было бы подменить уже после проверки.
  • Экономия памяти (String Pool). Раз строку нельзя менять, одинаковые литералы можно безопасно переиспользовать — об этом ниже.
  • Кэш hashCode. Хеш считается один раз и запоминается (строка же не меняется) — это ускоряет строки как ключи в HashMap.
  • Потокобезопасность. Неизменяемый объект можно шарить между потоками без блокировок.

Зачем отдельный String Pool? Это область памяти, где Java хранит строковые литералы. Все одинаковые литералы ("Hi" в разных местах программы) ссылаются на один объект в пуле — огромная экономия памяти. Это работает только потому, что строки неизменяемы: иначе изменение одной строки сломало бы все ссылки на неё.

StringBuilder. Из-за неизменяемости каждый s += x создаёт новую строку. В цикле это гора мусора. Когда склеиваешь много — бери StringBuilder: он меняет один буфер на месте.

Под капотом

Как строки ссылаются и где лежат:

String Pool (общий) "Hi" a b a и b → один объект, поэтому a == b: true new String("Hi") — отдельный объект в куче "Hi" c c → свой объект, поэтому a == c: false

Литералы "Hi" берутся из пула (один объект на всех). new String("Hi") принудительно создаёт отдельный объект в куче. Поэтому для строк всегда equals, а не ==.

Immutable + HashMap — зачем это. Строки чаще всего и используют как ключи в HashMap. Map раскладывает ключи по hashCode. Так как строка неизменяема:

  • её hashCode никогда не меняется (и кэшируется) → ключ всегда находится в своей «корзине»;
  • если бы строку-ключ можно было изменить после вставки, её hashCode стал бы другим → запись потерялась бы, Map искал бы её не там.

Поэтому неизменяемость — это то, что делает строку надёжным ключом.

🎤 Закрыл тему, если можешь объяснить:
• почему строки неизменяемы и зачем `equals` вместо `==`;
• что такое String Pool и зачем он (если дошёл до 2-го слоя);
• почему неизменяемость делает строку хорошим ключом HashMap (если дошёл до 3-го слоя).