[java] 자바 문자열 :“String s = new String (”silly“);”

저는 Java를 배우는 C ++ 사람입니다. 효과적인 Java를 읽고 있는데 뭔가 혼란 스러웠습니다. 다음과 같은 코드를 작성하지 말라고합니다.

String s = new String("silly");

불필요한 String물건을 만들기 때문입니다. 그러나 대신 다음과 같이 작성해야합니다.

String s = "No longer silly";

지금까지는 괜찮아요 …하지만이 수업이 주어지면 :

public final class CaseInsensitiveString {
    private String s;
    public CaseInsensitiveString(String s) {
        if (s == null) {
            throw new NullPointerException();
        }
        this.s = s;
    }
    :
    :
}

CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
String s = "polish";
  1. 첫 번째 진술은 왜 괜찮습니까? 안돼

    CaseInsensitiveString cis = "Polish";

  2. 어떻게해야합니까 CaseInsensitiveString처럼 행동 String때문에 위의 문 (와 연장없이 OK입니다 String)? 리터럴을 그대로 전달할 수 있도록하는 것은 String에 대해 무엇입니까? 내 이해에서 Java에는 “복사 생성자”개념이 없습니까?



답변

String언어의 특수 내장 클래스입니다. 말을 피해야 하는 String수업 만을 위한 것입니다.

String s = new String("Polish");

리터럴 "Polish"은 이미 유형 String이고 불필요한 개체를 추가로 생성하고 있기 때문입니다 . 다른 수업의 경우

CaseInsensitiveString cis = new CaseInsensitiveString("Polish");

해야 할 올바른 (그리고이 경우에만) 일입니다.


답변

리터럴 형식 (즉, new String ( “foo”)이 아닌 “foo”)을 사용할 때의 주요 이점은 모든 문자열 리터럴이 VM에 의해 ‘인턴’된다는 것입니다. 즉, 동일한 문자열을 생성하는 다른 코드가 새 인스턴스를 생성하는 대신 풀링 된 문자열을 사용하도록 풀에 추가됩니다.

설명을 위해 다음 코드는 첫 번째 줄에 대해 true를 인쇄하고 두 번째 줄에 대해서는 false를 인쇄합니다.

System.out.println("foo" == "foo");
System.out.println(new String("bar") == new String("bar"));


답변

문자열은 자바에서 약간 특별하게 취급되며 불변이므로 참조 계수로 처리하는 것이 안전합니다.

쓰면

String s = "Polish";
String t = "Polish";

그런 다음 s와 t는 실제로 동일한 객체를 참조하고 s == t는 “==”객체에 대해 true를 반환합니다. 객체가 “is the same object”라고 읽습니다 (또는 어쨌든 이것이 다음의 일부인지 확실하지 않습니다. 실제 언어 사양 또는 단순히 컴파일러 구현의 세부 사항-따라서 이것에 의존하는 것이 안전하지 않을 수 있습니다).

당신이 쓰면

String s = new String("Polish");
String t = new String("Polish");

s! = t (명시 적으로 새 문자열을 만들었 기 때문에) s.equals (t)는 true를 반환하지만 (문자열이이 동작을 같음에 추가하기 때문에).

당신이 쓰고 싶은 것은

CaseInsensitiveString cis = "Polish";

따옴표가 객체에 대한 일종의 단락 생성자라고 생각하기 때문에 작동하지 않습니다. 사실 이것은 평범한 오래된 java.lang.Strings에서만 작동합니다.


답변

String s1="foo";

리터럴은 풀에 들어가고 s1은 참조합니다.

String s2="foo";

이번에는 “foo”리터럴이 StringPool에서 이미 사용 가능한지 여부를 확인하므로 s2가 동일한 리터럴을 참조합니다.

String s3=new String("foo");

“foo”리터럴은 먼저 StringPool에 생성 된 다음 string arg 생성자를 통해 String Object가 생성됩니다. 즉, new 연산자를 통한 객체 생성으로 인해 힙에 “foo”가 생성되고 s3가이를 참조합니다.

String s4=new String("foo");

s3와 동일

그래서 System.out.println(s1==s2);// **true** due to literal comparison.

System.out.println(s3==s4);// **false** due to object

비교 (s3 및 s4는 힙의 다른 위치에 생성됨)


답변

Strings는 Java에서 특별 String합니다. 불변이며 문자열 상수는 자동으로 객체 로 변환 됩니다.

당신을위한 방법이 없습니다 SomeStringClass cis = "value" 예제를 다른 클래스에 적용 할 .

으로 String선언 되었기 때문에 확장 할 수도 final없습니다. 이는 하위 클래스가 허용되지 않음을 의미합니다.


답변

Java 문자열은 흥미 롭습니다. 응답이 몇 가지 흥미로운 점을 다룬 것 같습니다. 여기 내 2 센트입니다.

문자열은 변경할 수 없습니다 (변경할 수 없음).

String x = "x";
x = "Y";
  • 첫 번째 줄은 문자열 값 “x”를 포함 할 변수 x를 만듭니다. JVM은 문자열 값 풀에서 “x”가 있는지 확인하고, 존재하는 경우 변수 x를 가리키고, 존재하지 않으면 생성 한 다음 할당을 수행합니다.
  • 두 번째 줄은 “x”에 대한 참조를 제거하고 “Y”가 문자열 값 풀에 있는지 확인합니다. 존재하는 경우 할당하고 그렇지 않은 경우 먼저 할당 한 다음 할당합니다. 문자열 값의 사용 여부에 따라 문자열 값 풀의 메모리 공간이 회수됩니다.

문자열 비교는 비교 대상에 따라 다릅니다.

String a1 = new String("A");

String a2 = new String("A");
  • a1 같지 않음 a2
  • a1a2객체 참조는
  • 문자열이 명시 적으로 선언되면 새 인스턴스가 생성되고 해당 참조는 동일하지 않습니다.

대소 문자를 구분하지 않는 클래스를 사용하려는 것이 잘못된 길에 있다고 생각합니다. 현은 그대로 두십시오. 정말로 관심있는 것은 값을 표시하거나 비교하는 방법입니다. 다른 클래스를 사용하여 문자열 형식을 지정하거나 비교하십시오.

TextUtility.compare(string 1, string 2)
TextUtility.compareIgnoreCase(string 1, string 2)
TextUtility.camelHump(string 1)

클래스를 구성하고 있으므로 원하는대로 비교를 수행 할 수 있습니다. 텍스트 값을 비교합니다.


답변

당신은 할 수 없습니다. Java에서 큰 따옴표로 묶인 것은 컴파일러에 의해 특별히 문자열로 인식되며, 불행히도이를 재정의 할 수 없습니다 (또는 확장 java.lang.String-선언 됨 final).