Обычно мы создаем объекты с помощью ключевого слова new
, например:
Object obj = new Object();
Строки - это объекты, но мы не используем new
для их создания:
String str = "Hello World";
Почему это? Могу ли я создать строку с new
?
Обычно мы создаем объекты с помощью ключевого слова new
, например:
Object obj = new Object();
Строки - это объекты, но мы не используем new
для их создания:
String str = "Hello World";
Почему это? Могу ли я создать строку с new
?
В дополнение к тому, что уже было сказано, String литералы [т.е. строки, такие как "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 Строковые литералы хороши, потому что они часто используются более одного раза. Например, рассмотрим (надуманный) код:
for (int i = 0; i < 10; i++) {
System.out.println("Next iteration");
}
Если у нас не было интернирования строк, "Следующая итерация" нужно было бы создать 10 раз, тогда как теперь он будет создан только один раз.
Строки являются "специальными" объектами в Java. Разработчики Java мудро решили, что Strings используются так часто, что им нужен собственный синтаксис, а также стратегия кэширования. Когда вы объявляете строку, говоря:
String myString = "something";
myString - ссылка на объект String со значением "something". Если вы позже объявите:
String myOtherString = "something";
Java достаточно умен, чтобы понять, что myString и myOtherString одинаковы и будут хранить их в глобальной таблице String как один и тот же объект. Он полагается на то, что вы не можете изменять Strings для этого. Это уменьшает объем требуемой памяти и ускоряет сравнение.
Если вместо этого вы пишете
String myOtherString = new String("something");
Java создаст для вас совершенно новый объект, отличный от объекта myString.
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").
Надеюсь, что это несколько сомнений.:)
Это ярлык. Первоначально это было не так, но Java изменила его.
Этот FAQ рассказывает об этом кратко. Об этом также говорит руководство по спецификации Java. Но я не могу найти его в Интернете.
Строка подвержена нескольким оптимизациям (из-за отсутствия лучшей фразы). Обратите внимание, что String также имеет перегрузку оператора (для оператора +) - в отличие от других объектов. Так что это особый случай.
В Java строки являются особым случаем со многими правилами, которые применяются только к строкам. Двойные кавычки заставляют компилятор создавать объект String. Поскольку объекты String неизменяемы, это позволяет компилятору ставить несколько строк и создавать более большой пул строк. Две одинаковые строковые константы всегда будут иметь одну и ту же ссылку на объект. Если вы не хотите, чтобы это было так, вы можете использовать новую строку 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
Когда загрузчик классов загружает класс, все String-константы добавляются в пул строк.
Невозможно создать новую строку с
String s = new String("I'm a new String");
Обычная нотация s = "new String";
- это более или менее удобный ярлык, который должен использоваться по соображениям производительности, за исключением тех редких случаев, где вам действительно нужны строки, которые соответствуют формуле p >
(string1.equals(string2)) && !(string1 == string2)
ИЗМЕНИТЬ
В ответ на комментарий: это был not, предназначенный для консультирования, а всего лишь прямой ответ на тезис опрошенных, что мы не используем ключевое слово "новое" для строк, которое просто неправда. Надеюсь, что это редактирование (в том числе и выше) немного разъясняет это. BTW - там есть несколько хороших и гораздо лучших ответов на вышеупомянутый вопрос о SO.
Синтаксический сахар.
String s = new String("ABC");
Синтаксис по-прежнему доступен.
Вы все еще можете использовать new String("string")
, но было бы сложнее создавать новые строки без строковых литералов... вам пришлось бы использовать массивы символов или байты:-) Строковые литералы имеют одно дополнительное свойство: все те же строковые литералы из любой класс указывает на тот же экземпляр строки (они интернированы).
Почти нет необходимости в новой строке, поскольку литерал (символы в кавычках) уже является объектом String, созданным при загрузке класса хоста. Совершенно законно ссылаться на методы на буквальном и донном, основное различие - удобство, предоставляемое литералами. Если бы нам пришлось создать массив символов и заполнить его char на char, и они будут делать новый массив String (char), это будет серьезной болью и потерей времени.
Литеральный пул содержит любые строки, которые были созданы без использования ключевого слова new
.
Есть разница: String без новой ссылки хранится в строковом литеральном пуле, а String с новым говорит, что они находятся в кучевой памяти.
Строка с новыми находится в другом месте в памяти, как и любой другой объект.
Поскольку String является неизменным классом в java.
Теперь почему он неизменен? Поскольку String является неизменным, поэтому он может быть разделен между несколькими потоками, и нам не нужно синхронизировать операцию String извне. Поскольку String также используется в режиме загрузки классов. Поэтому, если String изменен, тогда java.io.writer можно было бы изменить на abc.xyz.mywriter
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");
Вывод:
True
Я создал два отдельных объекта, у обоих есть поле (ref) 'Name'. Поэтому даже в этом случае "Ян Питер" является общим, если я понимаю, как работают java.