Строки являются объектами в Java, так почему бы нам не использовать «new» для их создания? - PullRequest
98 голосов
/ 06 января 2010

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

Object obj = new Object();

Строки являются объектами, но мы не используем new для их создания:

String str = "Hello World";

Почему это? Могу ли я сделать строку с new?

Ответы [ 14 ]

124 голосов
/ 06 января 2010

В дополнение к тому, что уже было сказано, строковые литералы [то есть строки типа "abcd", но не new String("abcd")] в Java интернированы - это означает, что каждый раз, когда вы ссылаетесь на "abcd" вы получаете ссылку на один String экземпляр, а не на новый каждый раз. Итак, у вас будет:

String a = "abcd";
String b = "abcd";

a == b; //True

но если бы у вас было

String a = new String("abcd");
String b = new String("abcd");

тогда возможно иметь

a == b; // False

(и если кому-то нужно напомнить, всегда используйте .equals() для сравнения строк; == тесты на физическое равенство).

Литералы Interning String хороши тем, что они часто используются более одного раза. Например, рассмотрим (надуманный) код:

for (int i = 0; i < 10; i++) {
  System.out.println("Next iteration");
}

Если бы у нас не было интернирования Strings, «Следующая итерация» должна была бы быть реализована 10 раз, тогда как теперь она будет создаваться только один раз.

30 голосов
/ 06 января 2010

Строки являются «специальными» объектами в Java. Разработчики Java мудро решили, что строки используются так часто, что им необходим собственный синтаксис, а также стратегия кэширования. Когда вы объявляете строку, говоря:

String myString = "something";

myString - ссылка на объект String со значением «что-то». Если позже вы заявите:

String myOtherString = "something";

Java достаточно умен, чтобы понять, что myString и myOtherString одинаковы и будут хранить их в глобальной таблице String как один и тот же объект. Это зависит от того факта, что вы не можете изменить строки для этого. Это снижает объем требуемой памяти и позволяет выполнять сравнения быстрее.

Если вместо этого вы пишете

String myOtherString = new String("something");

Java создаст для вас совершенно новый объект, отличный от объекта myString.

16 голосов
/ 02 апреля 2013
String a = "abc"; // 1 Object: "abc" added to pool

String b = "abc"; // 0 Object: because it is already in the pool

String c = new String("abc"); // 1 Object

String d = new String("def"); // 1 Object + "def" is added to the Pool

String e = d.intern(); // (e==d) is "false" because e refers to the String in pool

String f = e.intern(); // (f==e) is "true" 

//Total Objects: 4 ("abc", c, d, "def").

Надеюсь, это прояснит некоторые сомнения. :)

6 голосов
/ 06 января 2010

Строка подвергается нескольким оптимизациям (из-за отсутствия лучшей фразы). Обратите внимание, что String также имеет перегрузку операторов (для оператора +) - в отличие от других объектов. Так что это очень особый случай.

6 голосов
/ 06 января 2010

Это ярлык. Первоначально это не было так, но Java изменила это.

В этом FAQ кратко говорится об этом. Об этом также говорится в руководстве по спецификации Java. Но я не могу найти его в Интернете.

4 голосов
/ 28 сентября 2018

Обычно мы используем строковые литералы, чтобы избежать создания ненужных объектов. Если мы используем оператор new для создания объекта String, то он будет каждый раз создавать новый объект.

Пример:

String s1=“Hello“;
String s2=“Hello“;
String s3= new String(“Hello“);
String s4= new String(“Hello“);

Для вышеуказанного кода в памяти:

enter image description here

2 голосов
/ 06 января 2010

В Java строки - это особый случай, многие правила которого применяются только к строкам. Двойные кавычки заставляют компилятор создавать объект String. Поскольку объекты String являются неизменяемыми, это позволяет компилятору интернировать несколько строк и создавать пул строк большего размера. Две одинаковые строковые константы всегда будут иметь одинаковую ссылку на объект. Если вы не хотите, чтобы это имело место, вы можете использовать новую строку (""), и это создаст объект строки во время выполнения. Метод intern () имел обыкновение быть общим, чтобы заставить динамически созданные строки проверяться по таблице поиска строк. Как только строка в интерне, ссылка на объект будет указывать на канонический экземпляр String.

    String a = "foo";
    String b = "foo";
    System.out.println(a == b); // true
    String c = new String(a);
    System.out.println(a == c); // false
    c = c.intern();
    System.out.println(a == c); // true

Когда загрузчик классов загружает класс, все строковые константы добавляются в пул строк.

0 голосов
/ 02 февраля 2016
TString obj1 = new TString("Jan Peter");                
TString obj2 = new TString("Jan Peter");                    

if (obj1.Name == obj2.Name)                 
    System.out.println("True");
else                
    System.out.println("False");

Выход:

Правда

Я создал два отдельных объекта, оба имеют поле (ref) «Имя». Так что даже в этом случае «Ян Питер» является общим, если я понимаю, как работает Java.

0 голосов
/ 25 сентября 2014

Потому что String является неизменным классом в Java.

Теперь, почему он неизменен? Поскольку String является неизменным, он может быть разделен между несколькими потоками, и нам не нужно синхронизировать операцию String извне. В качестве String также используется механизм загрузки классов. Так что, если бы String был изменяемым, тогда java.io.writer можно было бы изменить на abc.xyz.mywriter

0 голосов
/ 26 сентября 2012

Литеральный пул содержит любые строки, созданные без использования ключевого слова new.

Существует различие: строка без новой ссылки сохраняется в пуле литералов String, а строка String with new говорит, что они находятся в динамической памяти.

Строка с новым находится в другом месте в памяти, как и любой другой объект.

...