programing

Java 문자열의 불변성

javaba 2022. 10. 26. 21:24
반응형

Java 문자열의 불변성

다음 예를 생각해 보겠습니다.

String str = new String();

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

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

자바 스트링 왜 인 거죠?str도와주세요!이것은 자바에서 문자열의 불변성과 모순되는 것이 아닐까요?누가 불변의 정확한 개념을 설명해 줄 수 있나요?

편집:

네, 알겠습니다만, 후속 질문 하나만 하겠습니다.다음 코드는 어떻게 됩니까?

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

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

, (「 「M!ss!pp!」가 참조 「M!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"

이제 우리가 할 수 있는 일은 아무것도1 없다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에서도 확인할 수 있습니다.프로의 힌트는, 실제로 어떻게 동작하고 있는지를 확인할 수 있습니다).그 기능은 다음과 같습니다.

  • '1'이 oldChar에서 현재 . 이 에는 모든 이 표시됩니다.oldCharnewChar.
  • 경우,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은 Cup Size -- 변수Pass-by-Value Please (Cup Size는 계속됩니다)를 읽어보는 것을 추천합니다.이것은 위의 글을 읽을 때 많은 도움이 될 것입니다.

읽어보셨나요?네. 좋습니다.

String str = new String();

에 의해, 「리모트 컨트롤」이라고불리는 컨트롤됩니다.str을 '어울리다'라는new String() (오류)""를 참조해 주세요.

예를 들어, 메모리에 다음과 같은 항목이 생성됩니다.

str --- > ""

str  = "Hello";

하면 .str 문자열인 "는 ."".

예를 들어, 메모리에 다음과 같은 항목이 생성됩니다.

str -+   ""
     +-> "Hello"

str = "Help!";

하면 .str 문자열인 "는 .""또는 리모트 컨트롤이 현재 가리키는 오브젝트.

예를 들어, 메모리에 다음과 같은 항목이 생성됩니다.

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

몇 개로 나누자

String s1 = "hello";

이 스테이트먼트는 hello를 포함하는 문자열을 생성하여 메모리(예: 고정 문자열 풀)에 공간을 차지하여 참조 객체 s1에 할당합니다.

String s2 = s1;

이 문에서는 새로운 참조 s2에 동일한 문자열 hello가 할당됩니다.

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

양쪽 참조가 같은 문자열을 가리키고 있기 때문에 다음과 같이 같은 값을 출력합니다.

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

String은 불변이지만 할당이 가능하기 때문에 s1새로운 값 스택을 참조합니다.

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

그러나 hello를 가리키는 s2 오브젝트는 그대로입니다.

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

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

String은 불변하기 때문에 Java Virtual Machine에서는 string s1을 메서드로 변경할 수 없습니다.다음과 같이 풀에 새로운 String 개체를 모두 만듭니다.

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

String이 변경 가능한 경우 출력은 다음과 같습니다.

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!

, 「」는 무시합니다.str포인터에 지나지 않습니다. 쓸 때 이에요.str = "Hello"; 하다, 하다, 하다, 하다, 하다, 하다, 하다를 str가리키고 있습니다.「 」를 재할당했을 strstr = "Help!"; 오브젝트가 생성됩니다."Hello"오브젝트는 Java가 가비지가 수집될 때마다 수집됩니다.

불변성은 인스턴스화된 객체의 값을 변경할 수 없음을 의미하며, "Hello!"를 "Help!"로 변환할 수 없습니다.

변수 str은 객체에 대한 참조로, str에 새 값을 할당하면 해당 값이 참조하는 객체의 값을 변경하지 않고 다른 객체를 참조하는 것입니다.

문자열 클래스는 불변이며 불변 객체의 값은 변경할 수 없습니다.그러나 String의 경우 string 값을 string 풀에 새 문자열이 생성되고 오래된 값이 아닌 문자열 참조보다 변경되면 string 값은 변경되지 않습니다.예를 들어보자.

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

문자열 "Mississippi"가 하나 생성되어 String 풀에 추가되므로 str은 현재 미시시피를 가리키고 있습니다.

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

그러나 위의 조작 후 다른 문자열이 "M!ss!ss!pp!"가 생성되고 문자열 풀에 추가됩니다.이 시점에서 str은 미시시피가 아닌 M!ss!ss!pp!를 가리키고 있습니다.

따라서 string 객체의 값을 변경하면 객체가 하나 더 생성되어 문자열 풀에 추가됩니다.

예를 하나 더 들어보겠습니다.

String s1 = "Hello"; 
String s2 = "World"; 
String s = s1 + s2;

위의 3행은 문자열 풀에 3개의 문자열 개체를 추가합니다.
1)) 1 1 1
2) ★★
World 3) Hello World

용도:

String s = new String("New String");
s.concat(" Added String");
System.out.println("String reference -----> "+s); // Output: String reference -----> New String

, 저는 기기, 가가 the the the the를 사용하고 .concat원래 문자열(즉, 문자열 "Added String")을 사용하여 "New String"을 변경하는 메서드입니다만, StringBuilder 클래스에서 이 작업을 수행하면 String 클래스의 오브젝트 참조를 변경할 수 없다는 것을 증명합니다.이하에 나타냅니다.

StringBuilder sb = new StringBuilder("New String");
sb.append(" Added String");
System.out.println("StringBuilder reference -----> "+sb);// Output: StringBuilder reference -----> New String Added String

라이너스 톨바즈의 말처럼:

말은 쉬운 겁니다.코드 표시

이것 좀 보세요.

public class Test{
    public static void main(String[] args){

        String a = "Mississippi";
        String b = "Mississippi";//String immutable property (same chars sequence), then same object

        String c = a.replace('i','I').replace('I','i');//This method creates a new String, then new object
        String d = b.replace('i','I').replace('I','i');//At this moment we have 3 String objects, a/b, c and d

        String e = a.replace('i','i');//If the arguments are the same, the object is not affected, then returns same object

        System.out.println( "a==b? " + (a==b) ); // Prints true, they are pointing to the same String object

        System.out.println( "a: " + a );
        System.out.println( "b: " + b );

        System.out.println( "c==d? " + (c==d) ); // Prints false, a new object was created on each one

        System.out.println( "c: " + c ); // Even the sequence of chars are the same, the object is different
        System.out.println( "d: " + d );

        System.out.println( "a==e? " + (a==e) ); // Same object, immutable property
    }
}

출력은

a==b? true
a: Mississippi
b: Mississippi
c==d? false
c: Mississippi
d: Mississippi
a==e? true

두 가지 사항을 기억하십시오.

  • 문자열은 조작 및 신규 작성 메서드를 적용할 때까지 변경되지 않습니다(c&d 케이스).
  • Replace 메서드는 두 매개 변수가 동일한 경우 동일한 String 개체를 반환합니다.

Java에서 String의 불변성을 해소하는 방법을 알고 싶다면...

코드

import java.lang.reflect.Field;

public class StringImmutability {
    public static void main(String[] args) {
        String str1 = "I am immutable";
        String str2 = str1;

        try {
            Class str1Class = str1.getClass();
            Field str1Field = str1Class.getDeclaredField("value");

            str1Field.setAccessible(true);
            char[] valueChars = (char[]) str1Field.get(str1);

            valueChars[5] = ' ';
            valueChars[6] = ' ';

            System.out.println(str1 == str2);
            System.out.println(str1);
            System.out.println(str2);           
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    }
}

산출량

true
I am   mutable
I am   mutable

문자열불변입니다., 참조만 변경할 수 있습니다.


String a = "a";
System.out.println("String a is referencing to "+a); // Output: a

a.concat("b");
System.out.println("String a is referencing to "+a); // Output: a

a = a.concat("b");
System.out.println("String a has created a new reference and is now referencing to "+a); // Output: ab

자바에서는 오브젝트는 일반적으로 참조에 의해 액세스 됩니다.코드 스트링에는 처음에 "Hello"(자동으로 생성되거나 상수 풀에서 가져온 개체)에 할당된 참조가 있으며, 그 다음 동일한 참조에 다른 개체 "Help!"를 할당했습니다.주의할 점은 참조가 동일하고 수정되었지만 객체가 다르다는 것입니다.코드에 있는 한 가지 더, 세 가지 오브젝트에 접근하셨는데

  1. 새로운 String()을 호출했을 때.
  2. 'hello'를 지정했을 때.
  3. "도움말!"을 할당했을 때.

새로운 String()을 호출하면 문자열 풀에 존재하더라도 새 개체가 생성되므로 일반적으로 사용하지 마십시오. String String()을 합니다.intern()★★★★★★ 。

이게 도움이 됐으면 좋겠어요.

불변성은 String 자체를 변경할 수 없다는 것입니다.값이 "abc"인 문자열 x가 있다고 가정합니다.이제 String을 변경할 수 없습니다. 즉, "abc"의 문자를 변경할 수 없습니다.

String에서 문자를 변경해야 할 경우 문자 배열을 사용하여 변환하거나 String Builder를 사용할 수 있습니다.

String x = "abc";
x = "pot";
x = x + "hj";
x = x.substring(3);
System.out.println(x);

char x1[] = x.toCharArray();
x1[0] = 's';
String y = new String(x1);
System.out.println(y);

출력:

hj
sj

또는 다음을 시도해 보십시오.

public class Tester
{
public static void main(String[] args)
{
 String str = "Mississippi"; 
 System.out.println(str); // prints Mississippi 
 System.out.println(str.hashCode());

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

해시 코드가 어떻게 변화하는지 보여줍니다.

문자열은 개체 자체는 변경할 수 없지만 개체에 대한 참조는 변경할 수 있음을 의미합니다.=를 "ty"라고 호출한 경우, 실제로 의 참조를 String 리터럴 "ty"에 의해 생성된 새 개체로 변경하는 것입니다.오브젝트 변경이란 예를 들어 메서드를 사용하여 필드 중 하나를 변경하는 것을 의미합니다(또는 필드는 퍼블릭이며 최종 필드가 아니므로 메서드를 통해 액세스하지 않고 외부에서 업데이트할 수 있습니다).

Foo x = new Foo("the field");
x.setField("a new field");
System.out.println(x.getField()); // prints "a new field"

예를 들어 String과 같은 불변 클래스(상속에 의한 변경을 방지하기 위해 final로 선언됨)에서는(메서드는 필드를 변경할 수 없으며 필드는 항상 비공개이며 final이 권장됨) 현재 String은 변경할 수 없지만 새로운 String을 반환할 수 있습니다.

String s = "some text";
s.substring(0,4);
System.out.println(s); // still printing "some text"
String a = s.substring(0,4);
System.out.println(a); // prints "some"

여기서 불변성은 인스턴스가 다른 참조를 가리킬 수 있지만 문자열의 원래 내용은 원래 참조에서 수정되지 않음을 의미합니다.당신이 준 첫 번째 예를 들어 설명하겠습니다.첫 번째 스트링은 "Hello"를 가리키고 있습니다.이것까지는 OK입니다.두 번째는 "Help!"를 가리킵니다.여기서 str은 "Help!"를 가리키기 시작했고 "Hello" 문자열의 참조가 손실되어 되돌릴 수 없습니다.

실제로 str이 기존 내용을 수정하려고 하면 다른 새로운 문자열이 생성되고 str이 해당 참조를 가리키기 시작합니다.따라서 원래 참조 문자열은 수정되지 않지만 참조 시 안전하며 객체의 인스턴스가 다른 참조를 가리키기 시작하므로 불변성이 유지됩니다.

답변이 매우 늦었지만 Java의 String 클래스 작성자가 보낸 간결한 메시지를 넣으려고 했습니다.

문자열은 일정하므로 생성된 후에는 값을 변경할 수 없습니다.문자열 버퍼는 가변 문자열을 지원합니다.String 객체는 불변하기 때문에 공유할 수 있습니다.

문자열을 변경하면 다른 개체(새 개체 또는 내부 개체 및 오래된 개체일 수 있음)가 반환된다는 것을 이 문서에서 알 수 있습니다.이에 대해 그다지 미묘한 힌트는 함수 시그니처에서 얻을 수 있습니다.'왜 그들은 객체에 대한 함수가 상태 대신 객체를 반환하도록 만들었을까?'라고 생각해 보세요.

public String replace(char oldChar, char newChar) 

또한 이 동작을 명확하게 하는 소스가 하나 더 있습니다(교체 기능 설명서 참조).

이 문자열에 포함된 모든 oldChar를 newChar로 대체한 새 문자열을 반환합니다.

출처 : https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#replace(char,%20char)

  • 작가 리 보인턴
  • 작가 아서 반 호프
  • 작가 마틴 부크홀츠
  • 작가 울프 지비스

출처 : JavaDoc of String.

오브젝트 문자열 - 메서드 자체는 "불변"하게 되어 있습니다.이 조작에서는, 「letters.replace("bbb", "aaa")」는 변경되지 않습니다.

단, 데이터를 할당하면 Strings 콘텐츠의 변경이 발생합니다.

    letters = "aaa";
    letters=null;
    System.out.println(letters);
    System.out.println(oB.hashCode());
    System.out.println(letters);
    letters = "bbbaaa";
    System.out.println(oB.hashCode());
    System.out.println(letters);

//오브젝트 문자열의 해시 코드는 변경되지 않습니다.

ifHELLO string 을 변경할 수 .HELLO로로 합니다.HILLO이 속성을 불변성 속성이라고 합니다.

여러 포인터 String 변수를 사용하여 HELLO String을 지정할 수 있습니다.

단, HELLO가 char Array일 경우 HELLO를 HAILLO로 변경할 수 있습니다.예:

char[] charArr = 'HELLO';
char[1] = 'I'; //you can do this

프로그래밍 언어에는 불변의 데이터 변수가 있으므로 키, 값 쌍의 키로 사용할 수 있습니다.

간단한 예를 들어 설명하겠습니다.


임의의 문자 배열(예: char a []={'h'',e'',l'',l'',o'}) 및 문자열(String s="hello";


문자 배열에서는 배열을 반복하여 마지막 세 글자만 인쇄하는 작업을 수행할 수 있지만 문자열에서는 새로운 String 개체를 만들고 필요한 하위 문자열을 복사해야 하며 주소는 새로운 String 개체에 포함됩니다.

예.

***String s="hello";
String s2=s.substrig(0,3);***

따라서 s2는 "hel"을 가집니다.

Java의 Unmutable 및 Final 문자열은 변경 및 변경이 불가능함을 의미합니다.

케이스 1:

class TestClass{  
 public static void main(String args[]){  
   String str = "ABC";  
   str.concat("DEF");  
   System.out.println(str);  
 }  
} 

출력: ABC

이유: 오브젝트 참조 스트링은 변경되지 않습니다.실제로 새로운 오브젝트 "DEF"가 생성되어 풀에 참조가 전혀 없습니다(손실).

케이스 2:

class TestClass{  
 public static void main(String args[]){  
   String str="ABC";  
   str=str.concat("DEF");  
   System.out.println(str);  
 }  
}  

출력: ABCDEF

이유: 이 경우 str은 새로운 오브젝트 "ABCDEF"를 참조하고 있기 때문에 ABCDEF를 출력합니다.즉, 이전의 str 오브젝트 "ABC"는 참조 없이 풀에서 손실됩니다.

String은 불변하기 때문에 반환된 함수의 값을 질문에서 string.so에 할당하지 않으면 변경이 발생하지 않습니다.

s=sarms(s, n1, n2); 문자열 s의 값이 변경됩니다.

프로그램 작성 시에도 변경되지 않은 값이 표시되어 있습니다(모든 순열을 제공하는 것은 아니지만, 예를 들어 질문에 대한 답변입니다).

여기 예가 있습니다.

> import java.io.*;  public class MyString { public static void
> main(String []args)throws IOException {  BufferedReader br=new
> BufferedReader(new InputStreamReader(System.in));  String
> s=br.readLine().trim(); int n=0;int k=0;  while(n!=s.length()) {
> while(k<n){  swap(s,k,n); System.out.println(s); swap(s,k,n); k++; }
> n++; } }  public static void swap(String s,int n1,int n2) { char temp;
> temp=s.charAt(n1); StringBuilder sb=new StringBuilder(s);
> sb.setCharAt(n1,s.charAt(n2)); sb.setCharAt(n2,temp); s=sb.toString();
> } }

하지만 위의 코드에서 문자열의 치환된 값을 얻지 못했습니다.그래서 저는 swap 함수의 반환값을 문자열에 할당하고 문자열의 변경값을 받았습니다. 반환값을 할당한 후 문자열의 환산값을 얻었습니다.

/import java.util.*; import java.io.*; public class MyString { public static void main(String []args)throws IOException{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); 
String s=br.readLine().trim(); int n=0;int k=0; 
while(n!=s.length()){ while(k<n){ s=swap(s,k,n); 
System.out.println(s); s=swap(s,k,n); k++; } n++; } } 
public static String swap(String s,int n1,int n2){
char temp; temp=s.charAt(n1); StringBuilder sb=new StringBuilder(s); sb.setCharAt(n1,s.charAt(n2)); sb.setCharAt(n2,temp); s=sb.toString(); return s; } }
    public final class String_Test {

    String name;
    List<String> list=new ArrayList<String>();

    public static void main(String[] args) {

        String_Test obj=new String_Test();
        obj.list.add("item");//List will point to a memory unit- i.e will have one Hashcode value #1234

        List<String> list2=obj.list; //lis1 also will point to same #1234

        obj.list.add("new item");//Hashcode of list is not altered- List is mutable, so reference remains same, only value in that memory location changes

        String name2=obj.name="Myname"; // name2 and name will point to same instance of string -Hashcode #5678
        obj.name = "second name";// String is Immutable- New String HAI is created and name will point to this new instance- bcoz of this Hashcode changes here #0089

        System.out.println(obj.list.hashCode());
        System.out.println(list2.hashCode());
        System.out.println(list3.hashCode());

        System.out.println("===========");
        System.out.println(obj.name.hashCode());
        System.out.println(name2.hashCode());
    }
}

이런 것을 생산하다

1419358369 1419358369

103056 65078777

불변 객체의 목적은 할당 후 값을 변경하지 않는 것입니다.구현에 따라 새 개체를 변경하려고 할 때마다 새 개체가 반환됩니다.주의: 이를 피하기 위해 문자열 대신 문자열 버퍼를 사용할 수 있습니다.

마지막 질문 :: 문자열 풀에 참조가 1개, 문자열이 2개 있습니다.단, 참조가 m!ss!ss!pp!를 가리킵니다.

언급URL : https://stackoverflow.com/questions/1552301/immutability-of-strings-in-java

반응형