Какова цель выражения "new String (...)" в Java?

При просмотре образцов онлайн-кода я иногда сталкиваюсь с назначением константы String объекту String с помощью нового оператора.

Например:

String s;
...
s = new String("Hello World");

Это, конечно, по сравнению с

s = "Hello World";

Я не знаком с этим синтаксисом и понятия не имею, какова цель или эффект. Поскольку константы String обычно сохраняются в пуле констант, а затем в любом представлении, которое JVM имеет для работы со строковыми константами, что-нибудь еще будет выделено в куче?

Ответ 1

Единственное место, где вам может понадобиться new String(String), - заставить подстроку копировать новый базовый массив символов, как в

small=new String(huge.substring(10,20))

Однако это поведение, к сожалению, недокументировано и зависит от реализации.

Я был сожжен этим при чтении больших файлов (до 20 MiB) в String и вырезании его в строки после факта. Я закончил со всеми строками для строк, ссылающихся на char [], состоящий из всего файла. К сожалению, это непреднамеренно содержало ссылку на весь массив для нескольких строк, на которые я держался, в течение более длительного времени, чем обработка файла - я был вынужден использовать new String(), чтобы обойти его.

Единственный способ реализации агностики:

small=new String(huge.substring(10,20).toCharArray());

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

Должен быть документированный способ получить новую строку, скопировав символы существующего; или документация String(String) должна быть улучшена, чтобы сделать ее более явной (там есть импликация, но она довольно расплывчата и открыта для интерпретации).

Pitfall Предполагая, что Doc не заявляет

В ответ на комментарии, которые продолжают поступать, обратите внимание на то, что реализована реализация Apache Harmony new String():

public String(String string) {
    value = string.value;
    offset = string.offset;
    count = string.count;
}

Правильно, никакой копии базового массива нет. И все же он по-прежнему соответствует документации (Java 7) String, в которой он:

Инициализирует вновь созданный объект String, чтобы он представлял ту же последовательность символов, что и аргумент; Другими словами, вновь созданная строка является копией строки аргумента. Если явная копия оригинала не нужна, использование этого конструктора необязательно, поскольку строки являются неизменяемыми.

Существенная часть - это "копия аргумента строка"; он не говорит "копия строки аргумента и базового массива символов, поддерживающих строку".

Будьте осторожны с тем, что вы программируете в документации, а не в одном.

Ответ 2

Единственный раз, когда я нашел это полезным, заключается в объявлении переменных блокировки:

private final String lock = new String("Database lock");

....

synchronized(lock)
{
    // do something
}

В этом случае инструменты отладки, такие как Eclipse, будут отображать строку при перечислении того, что блокирует текущий поток или ожидает его. Вы должны использовать "новую строку", т.е. Выделить новый объект String, поскольку в противном случае общий строковый литерал может быть заблокирован каким-либо другим несвязанным кодом.

Ответ 3

Строка s1 = "foo" ; литерал войдет в StringPool и s1 будет ссылаться.

String s2 = "foo" ; на этот раз он проверит, что литерал "foo" уже доступен в StringPool или нет, поскольку теперь он существует, поэтому s2 будет ссылаться на один и тот же литерал.

String s3 = new String ( "foo" ); "foo" литерал будет создан в StringPool сначала, а затем через конструктор строковых аргументов String Object будет создан, т.е. "foo" в куче из-за создание объекта с помощью нового оператора, тогда s3 будет ссылаться на него.

Строка s4 = новая строка ( "foo" ); такая же, как s3

so System.out.println(s1 == s2);// true из-за сравнения букв.

и System.out.println(s3 == s4);// false из-за сравнения объектов (s3 и s4 создаются в разных местах в куче)

Ответ 4

Единственная утилита для этого конструктора, описанная Software Monkey и Ruggs, похоже, исчезла из JDK7. В классе String больше нет поля offset, а подстрока всегда использует

Arrays.copyOfRange(char[] original, int from, int to) 

чтобы обрезать массив char для копии.

Ответ 5

Ну, это зависит от того, что в этом примере есть "...". Если это StringBuffer, например, или массив байтов, или что-то еще, вы получите строку, построенную из данных, которые вы передаете.

Но если это просто другая строка, как в new String("Hello World!"), тогда она должна быть заменена просто "Hello World!", во всех случаях. Строки неизменяемы, поэтому клонирование нецелесообразно - более просто и менее эффективно создавать новый объект String только для дублирования существующей строки (будь то литеральная или другая переменная String, которую вы уже имеете).

Фактически, эффективная Java (что я настоятельно рекомендую) использует именно это как один из примеров "Избегайте создания ненужных объектов":


В качестве крайнего примера того, что не нужно делать, рассмотрите это утверждение:

String s = new String("stringette");  **//DON'T DO THIS!**

(Эффективная Java, второе издание)

Ответ 6

Как правило, это указывает на кого-то, кто не устраивает новый стиль С++, объявляющий при инициализации.

В дни C не считалась хорошей формой для определения автоматических переменных во внутренней области; С++ устранил ограничение парсера, и Java расширила это.

Итак, вы видите код с

int q;
for(q=0;q<MAX;q++){
    String s;
    int ix;
    // other stuff
    s = new String("Hello, there!");
    // do something with s
}

В крайнем случае все объявления могут находиться в верхней части функции, а не в закрытых областях, таких как цикл for.

В целом, однако, эффект этого заключается в том, чтобы вызвать String ctor, который вызывается один раз, и полученная String выбрасывается. (Желание избежать этого - это то, что привело Stroustrup, чтобы разрешать объявления в любом месте кода.) Итак, вы правы, что это не нужно и плохой стиль в лучшем случае и, возможно, даже плохой.

Ответ 7

Я думаю, это будет зависеть от образцов кода, которые вы видите.

В большинстве случаев использование конструктора классов "new String()" в образце кода только для того, чтобы показать очень хорошо известный Java-класс вместо создания нового.

Вам следует избегать его использования в большинстве случаев. Не только потому, что строковые литералы интернированы, но главным образом потому, что строка не поддается. Не имеет смысла иметь две копии, которые представляют один и тот же объект.

В то время как статья, навязанная Руггсом, "интересна", она не должна использоваться, если не очень конкретные обстоятельства, потому что она может нанести больше урона, чем пользы. Вы будете кодировать реализацию, а не спецификацию, и тот же код не может работать так же, например, в JRockit, IBM VM или другой.

Ответ 8

Существует два способа создания строк в Java. Ниже приведены примеры обоих способов: 1) Объявите переменную типа String (класс в Java) и присвойте ей значение, которое должно быть помещено между двойными кавычками. Это создаст строку в области пула строк в памяти. например: String str = "JAVA";

2) Используйте конструктор класса String и передайте строку (в двойных кавычках) в качестве аргумента. например: String s = новая строка ( "JAVA" ); Это создаст новую строку JAVA в основной памяти, а также в пуле строк, если эта строка еще не присутствует в пуле строк.