[java] Java에서 문자열의 불변성

다음 예를 고려하십시오.

String str = new String();

str  = "Hello";
System.out.println(str);  //Prints Hello

str = "Help!";
System.out.println(str);  //Prints Help!

이제 Java에서 String 객체는 변경할 수 없습니다. 그런 다음 개체에 어떻게 str“도움말!”값을 할당 할 수 있습니까? 이것이 Java에서 문자열의 불변성과 모순되지 않습니까? 아무도 불변성의 정확한 개념을 설명해 주시겠습니까?

편집하다:

확인. 나는 지금 그것을 받고 있지만 하나의 후속 질문입니다. 다음 코드는 어떻습니까?

String str = "Mississippi";
System.out.println(str); // prints Mississippi 

str = str.replace("i", "!");
System.out.println(str); // prints M!ss!ss!pp! 

이것은 두 개의 객체 ( “Mississippi”와 “M! ss! ss! pp!”)가 다시 생성되고 참조가 방법 str후에 다른 객체를 가리키는 것을 의미 replace()합니까?



답변

str객체가 아니라 객체에 대한 참조입니다. "Hello"그리고 "Help!"두 개의 구별되는 String객체. 따라서 문자열을 str 가리 킵니다 . 당신은 무엇을 변경할 수 있습니다 가리키는 것이 아니라 어떤 것을 가리키고있다 .

이 코드를 예로 들어 보겠습니다.

String s1 = "Hello";
String s2 = s1;
// s1 and s2 now point at the same string - "Hello"

이제 아무것도 없다 에 우리가 할 수있는 s1그 값에 영향을 미칠 것입니다 s2. 그것들은 같은 객체 (문자열)를 참조 "Hello"하지만 그 객체는 불변이므로 변경할 수 없습니다.

우리가 이런 식으로하면 :

s1 = "Help!";
System.out.println(s2); // still prints "Hello"

여기에서 객체를 변경하고 참조를 변경하는 것의 차이점을 볼 수 있습니다. s2여전히 초기에 설정 한 것과 동일한 객체 s1를 가리 킵니다. 설정 s1"Help!"단지 변경하는 것은 참조 그동안, String원래 그대로 남아 지칭 개체.

문자열 변경 가능하면 다음과 같이 할 수 있습니다.

String s1 = "Hello";
String s2 = s1;
s1.setCharAt(1, 'a'); // Fictional method that sets character at a given pos in string
System.out.println(s2); // Prints "Hallo"

OP의 편집에 응답하도록 편집 :

String.replace (char, char)소스 코드를 살펴보면 ( JDK 설치 디렉토리의 src.zip에서도 사용 가능) 실제로 어떻게 작동하는지 궁금 할 때마다 살펴 보는 것이 좋습니다. 다음과 같습니다.

  • oldChar현재 문자열에 하나 이상의 발생이 있는 경우 모든 발생이 oldChar로 대체 되는 현재 문자열의 사본을 작성하십시오 newChar.
  • (가) 경우 oldChar현재 문자열에 존재하지 않는, 현재의 문자열을 반환합니다.

예, "Mississippi".replace('i', '!')String객체를 만듭니다 . 다시 말하지만 다음과 같습니다.

String s1 = "Mississippi";
String s2 = s1;
s1 = s1.replace('i', '!');
System.out.println(s1); // Prints "M!ss!ss!pp!"
System.out.println(s2); // Prints "Mississippi"
System.out.println(s1 == s2); // Prints "false" as s1 and s2 are two different objects

지금 당신의 숙제는 위의 코드가 변경 않을 경우 무엇을 보는 것입니다 s1 = s1.replace('i', '!');s1 = s1.replace('Q', '!');🙂


1 실제로 문자열 (및 기타 불변 객체)을 변경 하는 것이 가능합니다. 리플렉션이 필요하고 매우 위험하며 프로그램을 실제로 파기하지 않는 한 절대 사용해서는 안됩니다.


답변

str참조 하는 객체 는 변경 될 수 있지만 실제 String객체 자체는 변경할 수 없습니다.

String문자열을 포함하는 객체 "Hello""Help!"따라서 그들은 불변하기 때문에, 그 값을 변경할 수 없다.

String객체 의 불변성이 객체를 가리키는 참조가 변경 될 수 없음을 의미하지는 않습니다.

str참조가 변경되는 것을 막을 수있는 한 가지 방법은 다음과 같이 선언하는 것입니다 final.

final String STR = "Hello";

이제 또 다른를 할당하려고 String하는 STR컴파일 오류가 발생합니다.


답변

Light_handle 변수Pass-by-Value Please (컵 크기 계속)에 대한 이야기컵 크기를 읽는 것이 좋습니다 . 위의 게시물을 읽을 때 많은 도움이 될 것입니다.

읽어 보셨습니까? 예. 좋은.

String str = new String();

“”라는 새로운 “원격 제어”를 작성하고이를 strnew String()(또는 "")으로 설정합니다.

예를 들어 메모리에서 다음을 생성합니다.

str --- > ""

str  = "Hello";

그러면 리모콘 ” str” 이 변경 되지만 원래 문자열은 수정되지 않습니다 "".

예를 들어 메모리에서 다음을 생성합니다.

str -+   ""
     +-> "Hello"

str = "Help!";

그러면 리모컨 ” str“이 (가) 변경되지만 원래 문자열 ""이나 리모컨이 현재 가리키는 객체는 수정되지 않습니다 .

예를 들어 메모리에서 다음을 생성합니다.

str -+   ""
     |   "Hello"
     +-> "Help!"


답변

몇 부분으로 나눕니다

String s1 = "hello";

이 문장은 메모리에 Hello 공간과 점유 공간을 포함하는 문자열 , 즉 상수 문자열 풀 을 생성하고이를 참조 객체 s1에 할당합니다.

String s2 = s1;

이 문장은 같은 문자열 hello 를 새로운 참조 s2에 할당합니다.

         __________
        |          |
s1 ---->|  hello   |<----- s2
        |__________| 

두 참조 모두 동일한 문자열을 가리 키므로 다음과 같은 값을 출력하십시오.

out.println(s1);    // o/p: hello
out.println(s2);    // o/p: hello

문자열변경할 수 없지만 할당이 가능하므로 s1 은 이제 새로운 값 스택을 참조합니다 .

s1 = "stack";
         __________
        |          |
s1 ---->|  stack   |
        |__________|

그러나 안녕하세요를 가리키는 s2 객체는 어떻 습니까 ?

         __________
        |          |
s2 ---->|  hello   |
        |__________|

out.println(s1);    // o/p: stack
out.println(s2);    // o/p: hello

String은 불변이므로 Java Virtual Machine은 메소드로 문자열 s1을 수정할 수 없습니다 . 다음과 같이 풀에 모든 새 문자열 객체를 만듭니다.

s1.concat(" overflow");

                 ___________________
                |                   |
s1.concat ----> |  stack overflow   |
                |___________________|

out.println(s1);    // o/p: stack
out.println(s2);    // o/p: hello
out.println(s1.concat); // o/p: stack overflow

문자열이 변경 가능하면 출력은

out.println(s1);    // o/p: stack overflow

이제 String에 concat () 과 같은 메소드 를 수정 한 이유가 놀랍습니다 . 스 니펫을 따르면 혼란이 사라집니다.

s1 = s1.concat(" overflow");

여기에서는 수정 된 문자열 값을 다시 s1 참조에 할당 합니다.

         ___________________
        |                   |
s1 ---->|  stack overflow   |
        |___________________|


out.println(s1);    // o/p: stack overflow
out.println(s2);    // o/p: hello

그래서 Java는 String을 최종 클래스 로 결정했습니다. 그렇지 않으면 누구나 문자열 값을 수정하고 변경할 수 있습니다. 이것이 조금 도움이되기를 바랍니다.


답변

처음 참조한 문자열 객체는 str변경되지 않았으므로 str새 문자열 객체를 참조하기 만하면됩니다.


답변

문자열은 변경되지 않으며 참조는 변경됩니다. 불변성과 final필드 개념을 혼동하고 있습니다. 필드가로 선언되면 final, 일단 할당 된 필드는 재 할당 할 수 없습니다.


답변

질문의 교체 부분과 관련하여 다음을 시도하십시오.

String str = "Mississippi";
System.out.println(str); //Prints Mississippi 

String other = str.replace("i", "!");
System.out.println(str); //still prints Mississippi 
System.out.println(other);  // prints M!ss!ss!pp!