문자열은 Java에서 객체이므로 'new'를 사용하여 생성하지 않는 이유는 무엇입니까?


104

일반적으로 new다음과 같은 키워드를 사용하여 객체를 만듭니다 .

Object obj = new Object();

문자열은 객체이지만이 new를 생성하는 데 사용하지 않습니다 .

String str = "Hello World";

왜 이런거야? 문자열을 만들 수 있습니까 new?


이 질문에 대해서도 살펴보아야합니다. stackoverflow.com/questions/456575/java-wrapper-equality-test
변경됨

1
문자열 리터럴은 이미 객체이기 때문입니다.
론의 후작

1
참고 new String(...)큰 문자열 substringing 때 구현 세부 사항을 회피하기 위해 사용되었다. 이것은 Java 7에서 수정되었으며 더 이상 필요하지 않습니다.
Thorbjørn Ravn Andersen

나는이 게시물의 100 번째 좋아요입니다. :)
Mukit09

답변:


130

이미 말한 것 외에도 Java에서 문자열 리터럴 [즉, 유사 "abcd"하지만 유사 하지 않은 문자열 new String("abcd")]이 인턴됩니다. 즉, "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");
}

문자열의 인턴이 없다면 "Next iteration"은 10 번 인스턴스화되어야하지만 지금은 한 번만 인스턴스화됩니다.


1
String a = new String ( "abcd")을 사용하면 비슷한 내용을 가진 두 개의 문자열이 메모리에 있음을 의미합니까?
변경됨

1
맞습니다-컴파일러는 그러한 문자열이 이미 인턴되었는지 확인하기 위해 반드시 확인하지는 않습니다 (확실히 그 문자열을 작성할 수는 있지만).
danben 2010 년

예,이 최적화는 문자열이 변경 불가능하므로 문제없이 공유 할 수 있기 때문에 가능합니다. 공유 된 "asdf"처리는 'Flyweight'디자인 패턴의 구현입니다.
manuel aldana 2010 년

아무도 그것이 가능하지 않다고 말하지 않았고, 그것이 보장되지 않는다고 말했습니다. 그게 당신의 반대표 였나요?
danben 2010 년

"== 객체 동등성 테스트"란 무엇을 의미합니까? 이것은 나에게 사실이 아닌 것 같지만 아마도 이것이 의미하는 것과 다른 것을 의미했을 것입니다.
Dawood ibn Kareem 2014

32

문자열은 Java에서 "특별한"개체입니다. 자바 설계자들은 문자열이 너무 자주 사용되어 캐싱 전략뿐만 아니라 자체 구문이 필요하다고 현명하게 결정했습니다. 다음과 같이 말하여 문자열을 선언 할 때 :

String myString = "something";

myString은 값이 "something"인 String 객체에 대한 참조입니다. 나중에 선언하는 경우 :

String myOtherString = "something";

Java는 myString과 myOtherString이 동일하고 동일한 객체로 전역 문자열 테이블에 저장된다는 것을 알아낼만큼 똑똑합니다. 이 작업을 수행하기 위해 문자열을 수정할 수 없다는 사실에 의존합니다. 이렇게하면 필요한 메모리 양이 줄어들고 더 빠르게 비교할 수 있습니다.

대신에

String myOtherString = new String("something");

Java는 myString 객체와는 다른 새로운 객체를 생성합니다.


헤이 ... 문자열 리터럴에 대한 일종의 구문 지원의 필요성을 인식하기 위해 "무한한 지혜"가 필요하지 않습니다. 다른 모든 심각한 프로그래밍 언어 디자인은 일종의 문자열 리터럴을 지원합니다.
Stephen C

12
과장은 기절, 선장 :) 감소하였습니다
제이미 McCrindle

16
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").

이것이 몇 가지 의심을 없애기를 바랍니다. :)


문자열 d = new String ( "def"); // 1 Object + "def"가 풀에 추가됨-> 여기서 "def"는 아직 풀에없는 경우에만 풀에 추가됩니다
southerton

@southerton 무의미합니다. 이미 수영장에 있습니다. 컴파일러에 의해 배치되었습니다.
Marquis of Lorne

@EJP 왜 (e == d)가 여기서 거짓입니까? 둘 다 풀에서 동일한 객체 "def"를 참조하고 있습니다. 맞습니까?
라자

문자열 c = new String ( "abc"); // 1 Object ...이 문장이 맞습니까? "abc"가 이미 상수 풀에서 참조 된 경우 inter 메소드의 사용은 무엇입니까?
프라 샨스 Debbadwar

6

지름길입니다. 원래는 그렇지 않았지만 Java가 변경했습니다.

FAQ 는 이에 대해 간략하게 설명합니다. Java 사양 가이드에서도 이에 대해 설명합니다. 하지만 온라인에서 찾을 수 없습니다.


2
끊어진 링크 및 변경된 다른 증거를 알지 못합니다.
Marquis of Lorne

1
@EJP 유용하다면 여전히 길을 잃은 기계에 있습니다.
Arjan

6

문자열은 몇 가지 최적화를 거쳐야합니다 (더 나은 문구를 원하기 위해). String에는 다른 객체와 달리 연산자 오버로딩 (+ 연산자의 경우)도 있습니다. 그래서 그것은 매우 특별한 경우입니다.


1
+는 실제로 StringBuilder.append (..) 호출로 변환되는 연산자입니다.
whiskeysierra

5

우리는 일반적으로 불필요한 객체 생성을 피하기 위해 문자열 리터럴을 사용합니다. new 연산자를 사용하여 String 객체를 생성하면 매번 새로운 객체를 생성합니다.

예:

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

메모리에있는 위 코드의 경우 :

여기에 이미지 설명 입력


2

Java에서 문자열은 특수한 경우이며 문자열에만 적용되는 많은 규칙이 있습니다. 큰 따옴표를 사용하면 컴파일러가 String 개체를 만듭니다. String 객체는 불변이므로 컴파일러가 여러 문자열을 인턴하고 더 큰 문자열 풀을 빌드 할 수 있습니다. 두 개의 동일한 문자열 상수는 항상 동일한 객체 참조를 갖습니다. 이 경우를 원하지 않는 경우 new 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 객체를 생성하게합니다." 저평가 주석
csguy

0

통사적인 설탕. 그만큼

String s = new String("ABC");

구문은 계속 사용할 수 있습니다.


1
이것은 옳지 않습니다. s = new String ( "ABC")은 s = "ABC"와 동일한 결과를 제공하지 않습니다. danben의 의견을 참조하십시오.
Steve B.

2
또한 다소 아이러니하게도 먼저 "ABC"인라인을 나타내는 String 인스턴스를 만든 다음 생성자 호출에 인수로 전달하여 동일한 값의 문자열을 반환합니다.
Andrzej Doyle

1
이 생성자의 유효한 사용 사례는이며 String small = new String(huge.substring(int, int));,이를 통해 char[]원본 huge문자열 에서 큰 기본을 재활용 할 수 있습니다 .
Pascal Thivent

1
@PascalThivent 예,하지만 Java 8에서는 더 이상 그렇지 않습니다. 더 이상 배열을 공유하지 않습니다 (G1을 사용한 자동 문자열 중복 제거 또는 향후 문자열 압축과 같은 다른 최적화를 준비하기 위해).
eckes

@AndrzejDoyle 맞지 않습니다. 컴파일러는 리터럴에 대한 개체를 만듭니다.
Marquis of Lorne

0

를 사용할 수는 new String("string")있지만 문자열 리터럴없이 새 문자열을 생성하는 것이 더 어려울 것입니다. 문자 배열 또는 바이트를 사용해야합니다. :-) 문자열 리터럴에는 하나의 추가 속성이 있습니다. 모든 클래스에서 동일한 문자열을 가리키는 모든 문자열 리터럴 인스턴스 (인턴).


0

리터럴 (따옴표로 묶인 문자)은 호스트 클래스가로드 될 때 이미 생성 된 String 개체이므로 문자열을 새로 만들 필요가 거의 없습니다. 리터럴과 돈에 대해 메서드를 호출하는 것은 완벽하게 합법적입니다. 주요 차이점은 리터럴이 제공하는 편의성입니다. char 배열을 만들고 char 단위로 채우고 새로운 String (char array)을 수행하면 tine의 큰 고통과 낭비가 될 것입니다.


0

새 문자열을 자유롭게 만들 수 있습니다.

String s = new String("I'm a new String");

일반적인 표기법 s = "new String";은 다소 편리한 지름길입니다. 꽤 드문 경우를 제외하고는 성능상의 이유로 사용해야합니다 . 방정식에 적합한 문자열이 실제로 필요한 경우

(string1.equals(string2)) && !(string1 == string2)

편집하다

댓글에 대응 : 이것은 한 하지 것으로, 질문자의 논문에 대한 조언을하지만, 단지 단지 직접적인 반응 의도 우리는 '새로운'키워드를 사용하지 않는 사실이 아닌 문자열을 위해. 이 편집 (위의 내용 포함)이 이것을 약간 명확히하기를 바랍니다. BTW-위의 질문에 대한 몇 가지 좋고 훨씬 더 나은 답변이 있습니다.


4
-1-나쁜 조언. new String(...)응용 프로그램에서 고유 한 ID를 가진 문자열을 생성하도록 요구 하지 않는 한 "자유롭게"사용해서는 안됩니다 .
Stephen C

1
알아요. 설명을 위해 게시물을 편집했습니다.
Andreas Dolk 2010 년

0

리터럴 풀에는 키워드를 사용하지 않고 생성 된 모든 문자열이 포함 new됩니다.

차이점이 있습니다. 새로운 참조가없는 문자열은 문자열 리터럴 풀에 저장되고 새로운 문자열은 힙 메모리에 있음을 나타냅니다.

new가있는 문자열은 다른 객체와 마찬가지로 메모리의 다른 곳에 있습니다.


0

String은 Java의 불변 클래스이기 때문입니다.

이제 왜 불변입니까? String은 불변이므로 여러 스레드간에 공유 할 수 있으며 String 작업을 외부에서 동기화 할 필요가 없습니다. As String은 클래스 로딩 메커니즘에서도 사용됩니다. 따라서 String이 변경 가능하면 java.io.writer가 abc.xyz.mywriter로 변경 될 수 있습니다.


0
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");

산출:

진실

두 개의 개별 개체를 만들었는데 둘 다 field (ref) 'Name'이 있습니다. 그래서이 경우에도 "Jan Peter"는 자바가 거래하는 방식을 이해하면 공유됩니다.


0

StringPool은 Java의 The Hashmap을 사용하여 구현됩니다. 항상 새 키워드로 생성하는 경우 String Pool에서 검색하지 않고 나중에 메모리 집약적 인 작업을 실행하고 성능에 영향을 미치는 새 키워드로 모든 문자열을 생성하는 경우 필요할 수있는 새 메모리를 생성합니다. 우리 응용 프로그램의. 따라서 문자열을 만드는 데 새 키워드를 사용하지 않는 것이 좋습니다. 왜냐하면 Hashmap이되는 String 풀로 이동하기 때문입니다 (메모리 저장, 새 키워드로 만든 많은 문자열이 있다고 상상해보세요) 여기에 저장되고 문자열이 이미 존재하는 경우 그 참조 (보통 스택 메모리에 상주 함)가 새로 생성 된 문자열로 반환됩니다. 따라서 성능을 향상시키기 위해 수행되었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.