Як можна ініціалізувати рядок за допомогою ""?


154

Якщо String - клас, як і будь-який інший, то як його можна ініціалізувати, використовуючи подвійні лапки?


25
Струна - це VIP-клас. " "це вже Рядок!
johnchen902

2
Немає особливого значення. Я просто мав на увазі Дуже важливе. Тобто java.lang.Stringмати спеціальну обробку мови Java.
johnchen902

16
Хто каже, що рядок - це "клас, як і будь-який інший"? Це дуже особливий клас, на відміну від будь-якого іншого. Оскільки ваше припущення є помилковим, питання насправді не відповідає.
Ерік Ліпперт

5
Тільки тому, що припущення помилкове, це не означає, що питання не відповідає. І правильна відповідь вже має 197 голосів.
Корай Тугай

Відповіді:


293

Java String - особливий

Дизайнери Java вирішили зберегти примітивні типи в об'єктно-орієнтованій мові, а не робити все об'єктом, щоб покращити продуктивність мови. Примітиви зберігаються в стеку викликів, де потрібно менше місця для зберігання і дешевше маніпулювати. З іншого боку, в купі програм зберігаються об'єкти, для яких потрібне складне управління пам’яттю та більше місця для зберігання.

З причини продуктивності Java String створений таким чином, щоб він знаходився між примітивом і класом.

Наприклад

String s1 = "Hello";              // String literal
String s2 = "Hello";              // String literal
String s3 = s1;                   // same reference
String s4 = new String("Hello");  // String object
String s5 = new String("Hello");  // String object

введіть тут опис зображення

Примітка: Строкові літерали зберігаються в загальному пулі. Це полегшує обмін пам’яті для рядків з однаковим вмістом для збереження пам’яті. StringОб'єкти, виділені за допомогою нового оператора, зберігаються у сховищі heapта немає спільного зберігання для того самого вмісту.


72
Зауважте, що "загальний пул", як правило, є частиною купи.
Йоахім Зауер

3
@JoachimSauer Так ... з невеликими перевагами :) додав, що в примітці. Дякую за запам'ятовування.
Суреш Атта

2
Так швидше написати String s1 = "Привіт"; ніж String s2 = new String ("Привіт") ;?
користувач2097804

28
Додам, що у вашому прикладі s1 == s2 == s3, але s4! = S5
Альфредо Озоріо

8
@AndrewJanke на останній точці jvm (7), рядок рядків не є в perm gen, і з Java 8 вже немає perm gen ...
assylias

50

Java трактує String як особливий клас, його можна ініціалізувати обома способами

  1. Безпосередньо присвоєння буквального

    String a = "adsasdf";
  2. Як і інші об'єкти, що використовують нове ключове слово

    String a = new String("adsasdf");

Вам потрібно бути особливо обережним, коли ви хочете порівняти зі ==знаком:

String a = "asdf";
String b = "asdf";
System.out.println(a == b);  // True
System.out.println(a.equals(b)); // True

String a = new String("asdf");
String b = new String("asdf");
System.out.println(a == b);  // False
System.out.println(a.equals(b)); // True

Це тому, що в першому випадку об'єкти a і b зберігаються у чомусь, що називається, literal poolі вони обидва посилаються на один і той же об'єкт, тому вони є рівними в обох напрямках.

Але у другому випадку a і b посилаються на різні об'єкти, наприклад, коли ми ініціалізуємо будь-які інші об'єкти. тому вони нерівні порівняно з ==оператором, тоді як вони рівні за значеннями.


18

String отримує особливу обробку в JLS: це один із двох непомітивних типів, для яких існують літерали (інший - *Class ) * .

Від JLS :

Строковий буквал - це посилання на екземпляр класу `String [...].

* ну, також є "нульовий тип" з його "нульовим буквальним" null, але більшість людей не вважають "нульовий тип" належним типом.


1
Мені також не було відомо про те, що "нульовий тип" є правильним типом на Java. Це дуже корисна інформація, ви повинні збільшити розмір шрифту.
Grijesh Chauhan

1
@GrijeshChauhan: ну, "нульовий тип" - це просто чудове формулювання, яке дозволяє будь-якому nullпризначити будь-яку змінну опорного типу. Інакше це не цікавий тип.
Йоахім Зауер

15

Це особливість мови Java. Строковим літералам у вихідному коді надається особлива обробка.

Мова специфікації, тут , просто говорить про те, що рядок літерал має Stringтип


5

Текст всередині подвійних лапок створює буквальний Stringоб’єкт.

String myString = "Some text";

Код вище створює Stringоб'єкт, використовуючи подвійні лапки.


4

Струни дуже часто використовуються в мові програмування. Оскільки java є об'єктно-орієнтованою, рядок є об'єктом. Щоб уникнути громіздкої нової струни ("someString"); оператор щоразу, коли вам потрібен об'єкт рядка, Java дозволяє вам просто створити об'єкт рядка, використовуючи літеральний рядок.

Але слід пам’ятати про рівність рядків. Ось короткий тест JUnit, щоб продемонструвати, що я маю на увазі.

    @Test
    public void stringTest() {
       // a string literal and a string object created 
       // with the same literal are equal
       assertEquals("string", new String("string"));

       // two string literals are the same string object
       assertSame("string", "string"); 

       // a string literal is not the same object instance 
       // as a string object created with the same string literal
       assertFalse("string" == new String("string"));

       // java's String.intern() method gives you the same
       // string object reference for all strings that are equal.
       assertSame("string", new String("string").intern());
    }

Якби ви могли лише ініціалізувати рядок new String(String src), тоді ви навіть не змогли б надати конструктору рядковий буквал. Вам потрібно було б ініціалізувати a char [], а потім використати пристрій String(char [] src)для конструювання рядка, або вам доведеться прочитати рядок з файлу.
AJMansfield

Це не правильно. Строковий буквал - це лише послідовність символів у вихідному файлі, оточеному подвійними лапки. Java автоматично створює екземпляр рядка за допомогою цього літералу. Тому буквальний і рядковий об'єкт рівні, але вони не однакові. Java також могла бути реалізована таким чином, що ви повинні використовувати новий String (""); інстанціювати об'єкт String, але це лише ускладнить наше життя. Отже, коли ви пишете нову String ("рядок"), java створює об'єкт String для прямої "string" і передає цей рядковий об'єкт до конструктора нової String.
René Link

2

Просто згадати. Строковий буквал - це посилання на екземпляр класу String, який ви можете написати таким чином:

 "abc" .getBytes ();

 "a: b: c" .split (":");

 "愛" .codePointAt (0);

2

- String - це клас на Java . Ви маєте рацію з цим, тому ми завжди можемо ініціалізувати newключове слово.

- Але коли ми робимо щось на кшталт:

String s = "";

Вищенаведене твердження позначено компілятором як спеціальний об'єкт String, а потім JVM під час завантаження класу (завантаження робиться перед ініціалізацією), бачить це те, що відомо як строковий літерал , який зберігається в пулу літеральних рядків .

- Отже, String можна створити за допомогою new()та ""методом, але останній надає рядковий літерал, який залишається в купі, навіть коли немає посилання на цей об'єкт рядка, оскільки він має посилання з пулу літеральних рядків.


2

Java виконує двоетапний процес для нас.

String str = "hello";

еквівалентно

char data[] = {'h', 'e', 'l' , 'l', 'o'};
String str = new String(data);

Як і. .NET] [1] отримав подібну річ.

String(Char[]) constructor

робить

String(char[] value)

Додавання посилань: -


2
Процес, який ви описуєте, - це не те, що робить насправді Java. Як вже говорили інші, "hello"це рядковий літерал і компілятор буде поставлений у постійний пул, див. JLS §3.10.5 та JVMS §5.1 .
siegi

1

Java.lang.Stringце не просто клас. Це невід'ємна частина основної мови. У компіляторі є синтаксичний цукор для нього. Наприклад, ""це як абревіатура для new String(""). Під час написання ""компілятор оптимізує однакові рядки до одного і того ж екземпляра, щоб заощадити місце."a" + 5 == "a5" ==> true

У компіляторі є синтаксичний цукор для багатьох речей, у тому числі не потрібно встановлювати / розкривати ящик між об’єктними версіями та їх рідними типами, немає батьківських засобів Об'єкт, конструктор за замовчуванням, ...


5
""не є абревіатурою для new String(""). Якщо ви користуєтесь "", перше, що буде зроблено, це шукати відповідники в басейні String JVM, і якщо це правда, вона поверне цю String. Використовуючи new String(""), ви завжди створюватимете нову String, навіть якщо сама String вже існує в пулі String (оскільки вона не буде зберігатися в пулі String).
g00glen00b

Я оновив свою відповідь. Чи використовують це люди на свою користь, наприклад, використовуючи рядкові константи, як еквівалент типу символу Lisp?
Сільвестер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.