Строки в Java

В Java String — это тип объекта, который может хранить последовательность символов, заключённую в двойные кавычки. Каждый символ занимает 16 бит, то есть используется кодировка UTF 16-bit. Строка ведёт себя аналогично массиву символов. Java предоставляет мощный и гибкий API для работы со строками, позволяющий выполнять различные операции, такие как конкатенация (concatenation), сравнение (comparison) и манипуляции (manipulation).

Пример:

String name = "Geeks";

String num = "1234"

Программа:


Java

// Java Program to demonstrate String
public class Geeks {

    // Главная функция
    public static void main(String args[]) {

        // создание Java строки с помощью ключевого слова new
        String str = new String("Geeks");

        System.out.println(str);
    }
}



Вывод

Geeks

Пример строк в Java

Способы создания строки в Java

Существует два способа создания строки в Java:

  • String literal (литерал строки)
  • Использование ключевого слова new

Синтаксис:

<String_Type> <string_variable> = "<sequence_of_string>";

1. Литерал строки (Static Memory)

Этот подход экономит память, так как новые объекты не создаются, если такой строковый литерал уже существует в пуле строк (string constant pool).

Пример:

String demoString = "GeeksforGeeks";

2. Использование ключевого слова new (Heap Memory)

  • String s = new String("Welcome");
  • В этом случае JVM создаст новый объект строки в обычной (не в пуле) области heap, а литерал «Welcome» будет размещён в пуле постоянных строк. Переменная s будет указывать на объект из heap.

В этом примере будет создан один объект. Сначала JVM не найдёт строку «Welcome» в пуле строк, поэтому создаст новый объект. После этого строка с таким значением уже появится в пуле, и при повторном использовании создаётся не новый объект, а возвращается ссылка на существующий.

Пример:

String demoString = new String("GeeksforGeeks");

Интерфейсы и классы для работы со строками в Java

  • CharBuffer: класс, реализующий интерфейс CharSequence. Позволяет использовать буферы символов там, где ожидается CharSequence. Пример использования — пакет регулярных выражений java.util.regex.
  • String: последовательность символов. В Java объекты String неизменяемы (immutable), то есть после создания их нельзя изменить.

Интерфейс CharSequence

CharSequence предназначен для представления последовательности символов в Java. Классы, реализующие этот интерфейс, предоставляют основные методы, такие как substring, lastOccurrence, firstOccurrence, concatenation, toUpperCase, toLowerCase и другие.

  1. String
  2. StringBuffer
  3. StringBuilder

1. String

Это класс с неизменяемыми объектами, то есть после создания его изменить нельзя. Чтобы изменить строку, нужно создать новый объект. Методы, такие как toUpperCase и toLowerCase, возвращают новый объект, не изменяя исходный. Класс автоматически обеспечивает безопасность при работе с потоками.

Синтаксис:

// Метод 1
String str= "geeks";

// Метод 2
String str= new String("geeks");

2. StringBuffer

StringBuffer — класс-партнёр String, но в отличие от него изменяемый (mutable) и потокобезопасный (thread safe). Его стоит использовать в многопоточной среде, когда объект StringBuffer разделяется между несколькими потоками. За счёт потокобезопасности возникает дополнительная нагрузка, поэтому класс применяют преимущественно в многопоточных программах.

Синтаксис:

StringBuffer demoString = new StringBuffer("GeeksforGeeks");

3. StringBuilder

StringBuilder является альтернативой String и StringBuffer. Он создаёт изменяемую последовательность символов, но не является потокобезопасным. Используется внутри одного потока, что не создаёт дополнительной нагрузки. В основном применяется в однопоточных программах.

Синтаксис:

StringBuilder demoString = new StringBuilder();
demoString.append("GFG");

4. StringTokenizer

Класс StringTokenizer предназначен для разбиения строки на токены (части).

Пример:

Объект StringTokenizer внутренне хранит текущую позицию в строке для токенизации. Некоторые операции двигают эту позицию вперёд. Токен возвращается в виде подстроки исходной строки, из которой был создан объект StringTokenizer.

StringJoiner — класс из пакета java.util, позволяющий создать последовательность строк, разделённую заданным разделителем и опционально начинающуюся с указанного префикса и заканчивающуюся суффиксом. Хотя такая операция реализуется и через StringBuilder с добавлением разделителя после каждой строки, StringJoiner упрощает этот процесс, сокращая объём кода.

Синтаксис:

public StringJoiner(CharSequence delimiter)

Ранее мы посмотрели, что строку можно создать с помощью литерала:

String demoString = "Welcome";

При создании JVM проверяет пул констант строк. Если строка отсутствует, создаётся новый объект, который помещается в пул. Если строка уже есть — создаётся ссылка на существующий объект. Кэш таких объектов называется String Constant Pool (пул констант строк). В версиях Java до JDK 6 пул располагался в области PermGen (Permanent Generation), а с JDK 7 был перенесён в основной Heap.

Неизменяемость строк в Java

В Java объекты строк являются неизменяемыми (immutable). Это значит, что они не могут быть изменены после создания. Если необходимо изменить строку, создаётся новый объект.

Пример:


Java

// Java Program to demonstrate Immutable String in Java
import java.io.*;

class Geeks {
    public static void main(String[] args) {
        String s = "Sachin";

        // Метод concat() добавляет строку в конец
        s.concat(" Tendulkar");

        // Выведется "Sachin",
        // так как строки являются неизменяемыми объектами
        System.out.println(s);
    }
}



Вывод

Sachin

Здесь строка «Sachin» не изменилась, но при вызове concat создаётся новый объект со значением “Sachin Tendulkar”. Вот почему строку называют неизменяемой.

Как видно, при создании строки создаются два объекта, но переменная s всё равно ссылается на «Sachin», а не на «Sachin Tendulkar». Если же явно присвоить результат метода concat() переменной, то она начнёт указывать на новый объект.

Пример: явное присваивание ссылки после конкатенации


Java

// Java Program to demonstrate Explicitly assigned strings
import java.io.*;

class Geeks {
    public static void main(String[] args) {
        String name = "Sachin";
        name = name.concat(" Tendulkar");
        System.out.println(name);
    }
}



Вывод

Sachin Tendulkar

Распределение памяти для строк в Java

Литерал строки

Когда объект String создаётся как литерал, он помещается в пул констант строк. Это позволяет JVM оптимизировать использование памяти. Пул расположен в области heap.

Пример 1: создание строки с помощью литерала

String str1 = "Hello";

Пример 2: создание двух строк с одинаковым значением через литералы

String str1 = "Hello";
String str2 = "Hello";

Использование ключевого слова new

Строку также можно создать с помощью оператора new, что выделит память динамически в области heap. Такие объекты не попадают в пул констант строк.

Пример 1: создание строк с помощью new

String str1 = new String("John");
String str2 = new String("Deo");

Если требуется поместить такую строку в пул, нужно вызвать метод intern().

Пример 2: использование intern() для добавления строки в пул

// добавит строку в пул констант строк
String internedString = demoString.intern();

Рекомендуется использовать литералы, так как это позволяет JVM эффективнее управлять памятью.

Обратите внимание: при использовании new или литералов строка хранится в памяти, но с помощью литералов и intern() объект попадает в пул констант внутри heap.

Пример создания строк разными способами:


Java

// Java Program to Declare a String
import java.io.*;
import java.lang.*;

class Geeks {
    public static void main(String[] args) {
      
        // Объявление строки без использования new
        String name = "GeeksforGeeks";

        // Вывод строки
        System.out.println("String name = " + name);

        // Объявление строки с использованием new
        String newString = new String("GeeksforGeeks");

        // Вывод второй строки
        System.out.println("String newString = " + newString);
    }
}



Вывод

String name = GeeksforGeeks
String newString = GeeksforGeeks

Примечание: объект String создаётся в области Heap, а литералы хранятся в специальной области памяти, известной как пул констант строк.

Перемещение пула строк из PermGen в обычный Heap

Область PermGen ограничена по размеру — обычно 64 МБ. Это создавало проблемы при создании и хранении большого количества строковых объектов. Чтобы решить эту проблему, пул строк был перемещён в общий Heap, который обычно имеет большой размер.

Для повышения эффективности Java стала использовать концепцию строковых литералов. При применении оператора ‘new’ JVM создаёт новый объект строки в обычной области heap, даже если аналогичный объект уже присутствует в пуле.

Пример:

String demoString = new String("Bhubaneswar");

Рассмотрим пример на Java, который поможет визуализировать структуру памяти JVM:

Реализация:


Java

// Java program to visualize JVM memory structure
class Geeks {
    public static void main(String args[]) {

      	// Объявление строк с помощью литералов
        String s1 = "TAT";
        String s2 = "TAT";

        // Объявление строк с использованием new
        String s3 = new String("TAT");
        String s4 = new String("TAT");

        // Вывод всех строк
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);
        System.out.println(s4);
    }
}



Вывод

TAT
TAT
TAT
TAT

Пул строк в Java

Примечание: все объекты в Java хранятся в heap. Ссылочные переменные находятся либо в стеке, либо внутри других объектов, тем самым тоже располагаясь в heap.

Пример 1:


Java

// Конструктор строки из подмассива байтов
// Класс с точкой входа
class Geeks {
    public static void main(String args[]) {

      	// Создание ASCII-массива
        byte ascii[] = { 71, 70, 71 };

      	// Создание строки из байтового массива
        String firstString = new String(ascii);
        System.out.println(firstString);

      	// Создание строки из байтового массива с указанием индексов
        String secondString = new String(ascii, 1, 2);
        System.out.println(secondString);
    }
}



Вывод

GFG
FG

Пример 2:


Java

// Создание строки из другой строки
class Geeks {
    public static void main(String args[]) {

      	// Массив символов
        char characters[] = { 'G', 'f', 'g' };

      	// Создание строки из массива символов
        String firstString = new String(characters);

      	// Создание строки из другой строки
        String secondString = new String(firstString);

        System.out.println(firstString);
        System.out.println(secondString);
    }
}



Вывод

Gfg
Gfg

🔑 Ключевые моменты:
— В Java строки представлены неизменяемыми объектами класса String — любые изменения создают новое значение.
— Строки можно создавать двумя способами: как литералы (хранятся в String Constant Pool) и с помощью оператора new (создаётся новый объект в heap).
— Интерфейс CharSequence реализуют основные классы для работы со строками: String, StringBuffer, StringBuilder.
— StringBuffer безопасен для многопоточного использования, StringBuilder — нет, и потому быстрее для однопоточных задач.
— Пул строк была перенесён из ограниченной области PermGen в основной Heap начиная с JDK 7, что улучшило управление памятью.

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *