Что такое строка (String) в Java и каковы её основные особенности?

Ответ

Строка (java.lang.String) — это неизменяемый (immutable) объект, представляющий последовательность символов Unicode. Это один из самых часто используемых классов в Java.

Главная особенность: Неизменяемость (Immutability)

  • Любая операция, модифицирующая строку (concat(), replace(), toLowerCase()), возвращает новый объект String.
  • Исходная строка остается неизменной.
  • Преимущества: Безопасность в многопоточности, возможность кэширования хэш-кода, использование в качестве ключей в HashMap.

Создание строк:

// 1. Литерал (попадает в String Pool)
String s1 = "Hello";

// 2. Через конструктор (создается новый объект в куче)
String s2 = new String("Hello");

// 3. Из массива символов
char[] chars = {'H', 'i'};
String s3 = new String(chars);

String Pool («пул строк»):

  • Специальная область в heap memory (куче) для хранения уникальных строковых литералов.
  • При создании через литерал ("text") JVM сначала ищет строку в пуле. Если находит — возвращает ссылку на существующий объект, если нет — создает новый в пуле.
  • Интернирование: Метод intern() помещает строку в пул или возвращает ссылку на уже существующую.
    String a = "hello";
    String b = new String("hello").intern();
    System.out.println(a == b); // true (ссылки на один объект в пуле)

Основные методы:

String str = " Java "

// Длина и символы
int len = str.length();          // 6
char ch = str.charAt(1);         // 'J'

// Модификация (создает новые строки)
String trimmed = str.trim();             // "Java"
String upper = str.toUpperCase();        // " JAVA "
String concat = str.concat("17");       // " Java 17"
String replaced = str.replace('a', 'o'); // " Jovo "

// Сравнение
boolean eq1 = str.equals(" java ");      // false (регистр)
boolean eq2 = str.equalsIgnoreCase(" java "); // true
int cmp = str.compareTo(" Ada ");       // положительное число

// Поиск и проверка
boolean starts = str.startsWith(" Ja"); // true
int index = str.indexOf('a');           // 2
boolean contains = str.contains("av");  // true

// Разделение и подстроки
String[] parts = "a,b,c".split(",");    // ["a", "b", "c"]
String sub = str.substring(1, 4);       // "Jav"

Производительность: Для частых модификаций используйте StringBuilder (небезопасен для потоков) или StringBuffer (потокобезопасный, но медленнее).

Ответ 18+ 🔞

Ну ты представляешь, этот ваш String в Java — это как будто священная корова, которую нельзя трогать. Ну то есть совсем, блядь. Объект, который раз и навсегда. Создал — и сиди любуйся, как на икону.

Самое главное — он неизменяемый, ёпта!

  • Захотел что-то сделать — concat, replace там — он тебе не меняет старый, а гордо выдает новый объект, как будто говоря: «На, мудила, довольствуйся этим».
  • Старая строка остается в неприкосновенности, как девственница в монастыре.
  • А плюсы-то какие: в потоках не перебьются, хэш-код закэшируют, в HashMap ключом можно тыкать без опаски.

Как его на свет произвести:

// 1. Литералом (прям в священный String Pool)
String s1 = "Hello"; // Идиллия

// 2. Через конструктор (создаст нового ублюдка в куче, даже если такой уже есть)
String s2 = new String("Hello"); // Зачем? Ну зачем так делать?

// 3. Из массива букв
char[] chars = {'H', 'i'};
String s3 = new String(chars); // Ну, бывает и такое

String Pool (он же «пул строк»):

  • Это такая VIP-зона в памяти, куда складывают все уникальные строчные литералы. Экономят место, хитрожопые.
  • Создал через кавычки — JVM сначала суёт нос в пул: «А такой урод уже есть?» Если есть — тыкает тебе ссылку на него. Нет — создаёт нового и в пул.
  • Интернирование (intern()): Это когда ты берешь свою самопальную строку и насильно засовываешь её в этот пул, либо получаешь ссылку на уже лежащую там.
    String a = "hello";
    String b = new String("hello").intern(); // Ну вот, теперь тоже в пуле
    System.out.println(a == b); // true (указывают на одного и того же ублюдка в пуле)

Чем его обычно тычут:

String str = " Java " // С пробелами, чтоб жизнь мёдом не казалась

// Померить и потрогать
int len = str.length();          // 6
char ch = str.charAt(1);         // 'J' (индексы с нуля, не забудь!)

// Поменять (помни — НОВЫЙ объект, старый не тронут!)
String trimmed = str.trim();             // "Java" (обрезал края)
String upper = str.toUpperCase();        // " JAVA " (орать начал)
String concat = str.concat("17");       // " Java 17" (прилепил хвост)
String replaced = str.replace('a', 'o'); // " Jovo " (поменял буковки)

// Сравнить, кто круче
boolean eq1 = str.equals(" java ");      // false (регистр, блядь, важен!)
boolean eq2 = str.equalsIgnoreCase(" java "); // true (а вот теперь похуй на регистр)
int cmp = str.compareTo(" Ada ");       // число положительное (значит, " Java " "больше")

// Поискать что-то в этом бардаке
boolean starts = str.startsWith(" Ja"); // true (начинается с)
int index = str.indexOf('a');           // 2 (первая буква 'a' тут)
boolean contains = str.contains("av");  // true (ну содержит и содержит)

// Порезать на куски
String[] parts = "a,b,c".split(",");    // ["a", "b", "c"] (разделил запятой)
String sub = str.substring(1, 4);       // "Jav" (вырезал кусок)

А теперь про производительность, ёбушки-воробушки:
Если ты собрался в цикле что-то там склеивать-переклеивать — это пиздец, товарищ. Каждая операция — новый объект. Для таких поделок есть StringBuilder (быстрый, но в потоках не дружит) или StringBuffer (потокобезопасный, но тормозит как черепаха в сиропе). Выбирай, что тебе дороже: скорость или спокойный сон.