«1. Введение

Java String — один из самых важных классов, и мы уже рассмотрели множество его аспектов в серии руководств, посвященных String.

В этом руководстве мы сосредоточимся на инициализации строк в Java.

2. Создание

Прежде всего, мы должны помнить, как создаются строки в Java.

Мы можем использовать ключевое слово new или литеральный синтаксис:

String usingNew = new String("baeldung");
String usingLiteral = "baeldung";

Также важно понимать, как строки управляются в специализированном пуле.

3. Объявление только строк

Во-первых, давайте просто объявим строку, без явного присвоения значения.

Мы можем сделать это либо локально, либо как переменная-член:

public class StringInitialization {

    String fieldString;

    void printDeclaredOnlyString() {
        String localVarString;
        
        // System.out.println(localVarString); -> compilation error
        System.out.println(fieldString);
    }
}

Как мы видим, если мы попытаемся использовать localVarString до присвоения ей значения, мы получим ошибку компиляции. С другой стороны, консоль покажет «null» для значения fieldString.

Видите, переменные-члены инициализируются значением по умолчанию при создании класса, нулевым в случае String. Но мы должны сами инициализировать локальные переменные.

Если мы присвоим localVarString значение null, мы увидим, что они теперь действительно равны:

String localVarString = null;
assertEquals(fieldString, localVarString);

4. Инициализация строки с использованием литералов

Давайте теперь создадим две строки, используя один и тот же литерал :

String literalOne = "Baeldung";
String literalTwo = "Baeldung";

Мы подтвердим, что создается только один объект, сравнив ссылки:

assertTrue(literalOne == literalTwo);

Причина этого восходит к тому факту, что строки хранятся в пуле. literalOne добавляет строку «baeldung» в пул, а literalTwo повторно использует ее.

5. Инициализация строки с помощью new

Однако мы увидим несколько иное поведение, если воспользуемся ключевым словом new.

String newStringOne = new String("Baeldung");
String newStringTwo = new String("Baeldung");

Хотя значение обеих строк будет таким же, как и раньше, на этот раз мы будем иметь разные объекты:

assertFalse(newStringOne == newStringTwo);

6. Пустые строки

Давайте теперь создадим три пустые строки: ~ ~~

String emptyLiteral = "";
String emptyNewString = new String("");
String emptyNewStringTwo = new String();

Как мы уже знаем, emptyLiteral будет добавлен в пул строк, а два других — непосредственно в кучу.

Хотя это не будут одни и те же объекты, все они будут иметь одно и то же значение:

assertFalse(emptyLiteral == emptyNewString)
assertFalse(emptyLiteral == emptyNewStringTwo)
assertFalse(emptyNewString == emptyNewStringTwo)
assertEquals(emptyLiteral, emptyNewString);
assertEquals(emptyNewString, emptyNewStringTwo);

7. Значения null

Наконец, давайте посмотрим, как ведут себя строки null.

Давайте объявим и инициализируем нулевую строку:

String nullValue = null;

Если бы мы напечатали nullValue, мы бы увидели слово «null», как мы видели ранее. И если бы мы попытались вызвать какие-либо методы для nullValue, то получили бы исключение NullPointerException, как и ожидалось.

Но почему печатается «null»? Что такое ноль на самом деле?

Спецификация JVM говорит, что null является значением по умолчанию для всех ссылок, поэтому оно не привязано конкретно к String. И на самом деле спецификация не требует какой-либо конкретной кодировки значения для null.

Итак, откуда тогда взялся «null» для печати строки?

Если мы посмотрим на реализацию PrintStream#println, то увидим, что она вызывает String#valueOf:

public void println(Object x) {
    String s = String.valueOf(x);
    synchronized (this) {
        print(s);
        newLine();
    }
}

И если мы посмотрим на String#valueOf, то получим ответ:

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

~ ~~ И, очевидно, это причина для «null».

8. Заключение

В этой статье мы рассмотрели инициализацию строк. Мы объяснили разницу между объявлением и инициализацией. Мы также коснулись использования нового и литерального синтаксиса.

Наконец, мы рассмотрели, что значит присвоить String нулевое значение, как нулевое значение представляется в памяти и как оно выглядит при печати.

Все примеры кода, использованные в статье, доступны на Github.