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
에서 현재 . 이 에는 모든 이 표시됩니다.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은 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
가리키고 있습니다.「 」를 재할당했을 str
str = "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!"를 할당했습니다.주의할 점은 참조가 동일하고 수정되었지만 객체가 다르다는 것입니다.코드에 있는 한 가지 더, 세 가지 오브젝트에 접근하셨는데
- 새로운 String()을 호출했을 때.
- 'hello'를 지정했을 때.
- "도움말!"을 할당했을 때.
새로운 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
'programing' 카테고리의 다른 글
MySQL에서 Maria로의 이행DB (0) | 2022.10.26 |
---|---|
JavaScript 개체의 크기를 가져오려면 어떻게 해야 합니까? (0) | 2022.10.26 |
문자열 "Jun 1 2005 1:33"을 변환합니다.PM"에서 날짜/시간으로 (0) | 2022.10.26 |
Python에서는 어떻게 무한한 수를 표현할 수 있을까요? (0) | 2022.10.26 |
기존 스트림에 새로운 가치 추가 (0) | 2022.10.26 |