Jak można zainicjować ciąg przy użyciu „”?


154

Jeśli String jest klasą taką samą jak każda inna, jak można ją zainicjować za pomocą podwójnych cudzysłowów?


25
String to klasa VIP. " "jest już Stringiem!
johnchen902

2
Bez specjalnego znaczenia. Miałem na myśli bardzo ważne. Oznacza to java.lang.Stringspecjalne traktowanie języka Java.
johnchen902

16
Kto powiedział, że string to „klasa jak każda inna”? To bardzo wyjątkowa klasa, inna niż wszystkie. Ponieważ twoje przypuszczenie jest fałszywe, nie da się odpowiedzieć na to pytanie.
Eric Lippert,

5
Tylko dlatego, że przypuszczenie jest fałszywe, nie oznacza to, że na pytanie nie można odpowiedzieć. A poprawna odpowiedź ma już 197 głosów.
Koray Tugay

Odpowiedzi:


293

Ciąg Java jest wyjątkowy

Projektanci Javy zdecydowali się zachować typy prymitywne w języku zorientowanym obiektowo, zamiast czynić wszystko obiektami, aby poprawić wydajność języka. Prymitywy są przechowywane w stosie wywołań, które wymagają mniej miejsca w pamięci i są tańsze w manipulowaniu. Z drugiej strony obiekty są przechowywane w stercie programu, co wymaga złożonego zarządzania pamięcią i większej ilości przestrzeni dyskowej.

Ze względu na wydajność, ciąg Java został zaprojektowany tak, aby znajdował się pomiędzy prymitywem a klasą.

Na przykład

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

wprowadź opis obrazu tutaj

Uwaga: Literały ciągów są przechowywane we wspólnej puli. Ułatwia to współdzielenie pamięci dla ciągów o tej samej zawartości, aby oszczędzać miejsce. Stringobiekty przydzielone za pośrednictwem nowego operatora są przechowywane w katalogu heapi nie ma współdzielenia magazynu dla tej samej zawartości.


72
Należy zauważyć, że „wspólna pula” jest zwykle częścią sterty.
Joachim Sauer,

3
@JoachimSauer Tak… z niewielkimi korzyściami :) dodał to w notatce. Dzięki za pamięć.
Suresh Atta

2
Czy więc szybciej napisać String s1 = "Hello"; niż String s2 = new String ("Hello") ;?
user2097804

28
Dodałbym, że w twoim przykładzie s1 == s2 == s3 ale s4! = S5
Alfredo Osorio

8
@AndrewJanke w najnowszym hotspocie jvm (7), puli ciągów nie ma w genach perm, a od Java 8 nie ma już genów perm ...
assylias

50

Java traktuje String jako specjalną klasę, możesz zainicjować na dwa sposoby

  1. Bezpośrednie przypisywanie literału

    String a = "adsasdf";
  2. Podobnie jak inne obiekty przy użyciu nowego słowa kluczowego

    String a = new String("adsasdf");

Musisz zachować szczególną ostrożność, gdy chcesz porównać ze ==znakiem:

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

Dzieje się tak dlatego, że w pierwszym przypadku obiekty a i b są przechowywane w czymś nazywanym literal pooli oba odnoszą się do tego samego obiektu, więc są równe w obu przypadkach.

Ale w drugim przypadku a i b odwołują się do różnych obiektów, tak jak wtedy, gdy inicjalizujemy inne obiekty. więc są nierówne w porównaniu z ==operatorem, podczas gdy mają równe wartości.


18

String jest traktowany w specjalny sposób w JLS: jest to jeden z dwóch niepierwotnych typów, dla których istnieją literały (drugi to Class) * .

Z JLS :

Literał łańcuchowy to odniesienie do instancji klasy `String [...].

* cóż, istnieje również „typ null” z jego „literałem null” null, ale większość ludzi nie uważa „typu null” za właściwy typ.


1
Nie wiedziałem również, że „typ zerowy” jest prawidłowym typem w Javie. To bardzo pomocne informacje, powinieneś zwiększyć rozmiar czcionki.
Grijesh Chauhan,

1
@GrijeshChauhan: cóż, "typ zerowy" to po prostu sprytne sformułowanie, które pozwala nullna przypisanie dowolnego do dowolnej zmiennej typu referencyjnego. W przeciwnym razie to nie jest interesujący typ.
Joachim Sauer

15

To cecha języka Java. Literały łańcuchowe w kodzie źródłowym są traktowane w specjalny sposób.

Specyfikacja języka mówi tutaj po prostu, że literał łańcuchowy jest Stringtypu


5

Tekst w cudzysłowie tworzy Stringobiekt literału .

String myString = "Some text";

Powyższy kod tworzy Stringobiekt, używając podwójnych cudzysłowów.


4

Łańcuchy są bardzo często używane w języku programowania. Ponieważ java jest zorientowana obiektowo, łańcuch jest obiektem. Aby uniknąć uciążliwego nowego ciągu znaków („someString”); instrukcja za każdym razem, gdy potrzebujesz obiektu typu string, java pozwala po prostu utworzyć obiekt typu string przy użyciu literału ciągu.

Należy jednak pamiętać o równości strun. Tutaj krótki test JUnit, aby pokazać, o co mi chodzi.

    @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());
    }

Gdybyś mógł tylko zainicjować łańcuch za pomocą new String(String src), nie byłbyś nawet w stanie nadać konstruktorowi literału ciągu. Musiałbyś zainicjować a char [], a następnie użyć String(char [] src)consructora do skonstruowania łańcucha, albo musiałbyś odczytać łańcuch z pliku.
AJMansfield,

To nie jest poprawne. Literał łańcuchowy to tylko sekwencja znaków w pliku źródłowym ujęta w podwójne cudzysłowy. Java automatycznie tworzy instancję łańcucha przy użyciu tego literału. Dlatego literał i obiekt String są równe, ale nie są tym samym. Java mogłaby być również zaimplementowana w ten sposób, że musisz użyć new String (""); utworzyć instancję obiektu String, ale to tylko utrudniłoby nam życie. Tak więc, kiedy piszesz nowy ciąg („ciąg”), java tworzy obiekt typu String dla literału „napis” i przekazuje ten obiekt ciągu do konstruktora nowego ciągu znaków.
René Link,

2

Wystarczy wspomnieć. Literał łańcuchowy to odniesienie do instancji klasy String, którą można napisać w następujący sposób:

 "abc" .getBytes ();

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

 „愛” .codePointAt (0);

2

- String to klasa w Javie . Masz rację, więc zawsze możemy zainicjować za pomocą newsłowa kluczowego.

- Ale kiedy robimy coś takiego:

String s = "";

Powyższa instrukcja jest oznaczana przez kompilator jako specjalny obiekt String, a następnie JVM podczas ładowania klasy (ładowanie odbywa się przed inicjalizacją), widzi to tak zwany literał ciągu , który jest przechowywany w puli literałów ciągu .

- Tak więc String można utworzyć za new()pomocą ""metody i, ale ta ostatnia dostarcza literał ciągu, który pozostaje w stercie nawet wtedy, gdy nie ma odniesienia do tego obiektu ciągu, ponieważ ma odniesienie z puli literałów ciągu.


2

Java wykonuje dla nas proces dwuetapowy.

String str = "hello";

jest równa

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

Podobnie jak [.NET] [1] ma podobną rzecz.

String(Char[]) constructor

robi

String(char[] value)

Dodawanie referencji: -


2
Proces, który opisujesz, nie jest tym, co faktycznie robi Java: jak już powiedzieli inni, "hello"jest to literał łańcuchowy i zostanie umieszczony w puli stałej przez kompilator, patrz JLS §3.10.5 i JVMS §5.1 .
siegi,

1

Java.lang.Stringto nie tylko klasa. To integralna część podstawowego języka. Kompilator ma do tego cukier syntaktyczny. Na przykład ""jest jak skrót od new String(""). Podczas pisania ""kompilator optymalizuje identyczne ciągi do tej samej instancji, aby zaoszczędzić miejsce."a" + 5 == "a5" ==> true

Kompilator ma cukier składniowy do wielu rzeczy, w tym brak konieczności pakowania / rozpakowywania między wersjami obiektów i ich rodzimymi typami, brak rodzica oznacza Object, domyślny konstruktor, ...


5
""nie jest skrótem od new String(""). Jeśli używasz "", pierwszą rzeczą, która zostanie zrobiona, jest wyszukanie dopasowań w puli String maszyny JVM i jeśli to prawda, zwróci ten ciąg. Używając new String(""), zawsze utworzysz nowy ciąg, nawet jeśli sam ciąg już istnieje w puli ciągów (ponieważ nie będzie przechowywany w puli ciągów).
g00glen00b

Zaktualizowałem odpowiedź. Czy ludzie używają tego na swoją korzyść, na przykład używając stałych łańcuchowych, takich jak odpowiednik typu symbolu Lispa?
Sylwester
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.