문자열은 변경할 수 없습니다. 의미가 정확히 무엇입니까? [복제]
- Java에서 문자열의 불변성 26 답변
불변 문자열에 다음 코드를 작성했습니다.
public class ImmutableStrings {
public static void main(String[] args) {
testmethod();
}
private static void testmethod() {
String a = "a";
System.out.println("a 1-->" + a);
a = "ty";
System.out.println("a 2-->" + a);
}
}
산출:
a 1-->a
a 2-->ty
여기서 변수의 값
a
이 변경되었습니다 (많은 사람들이 불변 객체의 내용을 변경할 수 없다고 말합니다). 그러나
String
불변
이라는 말의 의미는 정확히 무엇 입니까? 이 주제를 명확하게 설명해 주시겠습니까?출처 :
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
불변성
의 소란을 계속 진행하기 전에
String
결론을 내리기 전에 클래스와 그 기능을 조금 살펴 보겠습니다 .이것이
String
작동 하는 방식입니다.
String str = "knowledge";
평소와 같이 이것은 포함하는 문자열을 생성
"knowledge"
하고 reference를 할당합니다
str
. 충분히 간단합니까? 더 많은 기능을 수행 할 수 있습니다.
String s = str; // assigns a new reference to the same string "knowledge"
아래 문장이 어떻게 작동하는지 봅시다 :
str = str.concat(" base");
문자열이에 추가
" base"
됩니다
str
. 그러나
String
객체가 불변 이기 때문에 어떻게 이것이 가능 합니까? 놀랍게도, 그렇습니다.위의 명령문이 실행될 때 VM은 값을 가져옵니다
String str
. 즉
"knowledge"
, 덧붙여서
" base"
값을줍니다
"knowledge base"
. 이제
String
s는 변경할 수 없으므로 VM은이 값을에 할당 할 수 없으므로
str
새
String
객체를 생성 하고 값
"knowledge base"
을 제공하며 참조를 제공합니다
str
.여기서 주목할 점은
String
객체는 불변이지만
참조 변수는
변경할 수 없다는 것입니다. 따라서 위의 예에서 새로 형성된
String
객체 를 참조하도록 참조한 이유 입니다.위의 예에서이 시점에는 두 개의
String
객체가 있습니다. 첫 번째 객체는 value로 작성하고
"knowledge"
by
s
로 표시하고 두 번째 객체
"knowledge base"
는로 지정합니다
str
. 그러나 기술적으로 우리는 세 가지
String
목표를 가지고 있으며, 세 번째 목표
"base"
는
concat
성명서 의 리터럴 입니다 .
문자열 및 메모리 사용에 대한 중요한 사실
우리는 또 다른 참조 무엇을 가지고 있지 않은 경우
s
에를
"knowledge"
? 우리는 그것을 잃었을 것입니다
String
. 그러나 여전히 존재했지만 참조가 없기 때문에 손실 된 것으로 간주됩니다. 아래에서 하나 더 예를보십시오
String s1 = "java";
s1.concat(" rules");
System.out.println("s1 refers to "+s1); // Yes, s1 still refers to "java"
무슨 일이야:
- 첫 번째 줄은 매우 간단합니다. 새 줄을 만들어
String
"java"
참조하십시오s1
. - 다음으로 VM은 또 다른 new를 생성
String
"java rules"
하지만 아무것도 참조하지 않습니다. 따라서 두 번째String
는 즉시 손실됩니다. 우리는 그것을 도달 할 수 없습니다.
참조 변수는
s1
여전히 원본을 참조합니다
String
"java"
.
String
객체를 수정하기 위해 객체에 적용되는 거의 모든 방법 은 새
String
객체를 만듭니다 . 그렇다면이
String
물체들은 어디로 갑니까? 음,
모든 프로그래밍 언어의 주요 목표 중이 메모리에 존재하고, 하나의 메모리를 효율적으로 사용할 수 있도록하는 것입니다.
응용 프로그램이 증가함에 따라 리터럴이 큰 메모리 영역을 차지하는
경우가 매우 String
많으며 이로 인해 중복성이 발생할 수도 있습니다.
따라서 Java를보다 효율적으로 만들기 위해
JVM은 "문자열 상수 풀"이라는 특수한 메모리 영역을 별도로 설정합니다.
컴파일러가
String
리터럴을 볼 때
String
풀에서를 찾습니다 . 일치하는 것이 있으면 새 리터럴에 대한 참조가 기존 항목
String
을 가리키고 새
String
오브젝트가 작성 되지 않습니다 . 기존
String
에는 단순히 하나 이상의 참조가 있습니다. 다음은
String
객체를 불변 으로 만드는 요점입니다 .에서
String
일정 수영장,
String
객체는 하나 이상의 참조를 가질 가능성이 높습니다.
여러 참조가 String
이를 모르더라도 동일하게 가리키는 경우, 참조 중 하나가 해당 String
값을 수정하면 좋지 않습니다 . 이것이 String
객체가 불변 인 이유 입니다.
글쎄,
누군가 String
클래스 의 기능을 재정의하면 어떻게 될까요?
즉 그 이유 클래스가 표시되어 그 아무도 그 방법의 동작을 재정의 할 수 있도록.
String
final
문자열은 변경할 수 없으므로 개체 자체는 변경할 수 없지만 개체에 대한 참조는 변경할 수 있습니다. 실행
a = "ty"
하면 실제로
a
String 리터럴로 만든 새 객체에 대한 참조가 변경
"ty"
됩니다.객체를 변경한다는 것은 메소드를 사용하여 필드 중 하나를 변경하는 것입니다 (또는 필드는 공개적이고 최종이 아니므로 메소드를 통해 액세스하지 않고 외부에서 업데이트 할 수 있음).
Foo x = new Foo("the field");
x.setField("a new field");
System.out.println(x.getField()); // prints "a new field"
변경 불가능한 클래스 (상속으로 선언되어 상속을 통한 수정을 방지하기 위해) (메서드가 필드를 수정할 수 없으며 필드는 항상 개인 필드이며 최종 필드로 권장 됨) (예 : 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"
당신은 무엇을 변경하고 있습니다
a
에 의미합니다
. 이 시도:
String a="a";
System.out.println("a 1-->"+a);
String b=a;
a="ty";
System.out.println("a 2-->"+a);
System.out.println("b -->"+b);
당신은 것을 볼
오브젝트
되는
a
다음
b
의미가 변경되지 않았습니다.코드가
a
참조 하는 객체를 변경하지 못하게 하려면 다음을 시도하십시오.
final String a="a";
문자열은
char[]
일련의
,
int
해당 배열에 대한 오프셋 및
int
길이를 포함합니다.예를 들어.
String s
문자열 참조를위한 공간을 만듭니다. 사본을 할당하면 해당 참조가 참조하는 객체가 수정되지만 수정되지는 않습니다.당신은 또한 알고 있어야
new String(s)
실제로 유용한 것은 없습니다. 단지 같은 배열, 오프셋 및 길이로 지원되는 다른 인스턴스를 만듭니다
s
. 그렇게 할 이유는 거의 없으므로 대부분의 Java 프로그래머는 나쁜 습관으로 간주합니다.Java 큰 따옴표로 묶인 문자열
"my string"
은 실제로
인터 닝 된 String
인스턴스
"bar"
에 대한 참조 이므로 코드에 나타나는 횟수에 관계없이 동일한 String 인스턴스에 대한 참조입니다.
"hello"는 풀링 된 하나의 인스턴스를
new String(...)
작성하고 풀링되지 않은 인스턴스를 작성합니다. 시도
System.out.println(("hello" == "hello") + "," + (new String("hello") == "hello") + "," + (new String("hello") == new String("hello")));
하고 볼 수 있습니다
true,false,false
불변은 동일한 참조 값을 변경할 수 없음을 의미합니다. 새 참조를 작성해야 할 때마다 새 메모리 위치를 의미합니다. 전의:
String str="abc";
str="bcd";
여기서, 위의 코드에서, 메모리에는 값을 저장하기위한 2 개의 블록이있다. 첫 번째 값은 "abc"이고 두 번째 값은 "bcd"이며, 두 번째 값은 첫 번째 값으로 대체되지 않는다.이것은 불변이라고 부릅니다.
예제에서 변수
a
는 문자열 객체의 인스턴스에 대한 참조 일뿐입니다. 말할 때
a = "ty"
실제로 문자열 객체를 변경하는 것이 아니라 문자열 클래스의 완전히 다른 인스턴스에서 참조를 가리키는 것입니다.
여기를 봐
class ImmutableStrings {
public static void main(String[] args) {
testmethod();
}
private static void testmethod() {
String a="a";
System.out.println("a 1-->"+a);
System.out.println("a 1 address-->"+a.hashCode());
a = "ty";
System.out.println("a 2-->"+a);
System.out.println("a 2 address-->"+a.hashCode());
}
}
산출:
a 1-->a
a 1 address-->97
a 2-->ty
a 2 address-->3717
This indicates that whenever you are modifying the content of immutable string object a
a new object will be created. i.e you are not allowed to change the content of immutable object. that's why the address are different for both the object.
You are not changing the object in the assignment statement, you replace one immutable object with another one. Object String("a")
does not change to String("ty")
, it gets discarded, and a reference to ty
gets written into a
in its stead.
In contrast, StringBuffer
represents a mutable object. You can do this:
StringBuffer b = new StringBuffer("Hello");
System.out.writeln(b);
b.append(", world!");
System.out.writeln(b);
Here, you did not re-assign b
: it still points to the same object, but the content of that object has changed.
You are actually getting a reference to a new string, the string itself is not being changed as it is immutable. This is relevant.
See
Immutable objects on Wikipedia
An immutable object is an object whose state cannot be modified after it is created.
So a = "ABC"
<-- immutable object. "a" holds reference to the object. And, a = "DEF"
<-- another immutable object, "a" holds reference to it now.
Once you assign a string object, that object can not be changed in memory.
In summary, what you did is to change the reference of "a" to a new string object.
String S1="abc";
S1.concat("xyz");
System.out.println("S1 is", + S1);
String S2=S1.concat("def");
System.out.println("S2 is", + S2);
This shows that once a string object is create it cannot be changed. EveryTime you need to create new and put in another String. S
I think the following code clears the difference:
String A = new String("Venugopal");
String B = A;
A = A +"mitul";
System.out.println("A is " + A);
System.out.println("B is " + B);
StringBuffer SA = new StringBuffer("Venugopal");
StringBuffer SB = SA;
SA = SA.append("mitul");
System.out.println("SA is " + SA);
System.out.println("SB is " + SB);
Java String
is immutable, String
will Store the value in the form of object. so if u assign the value String a="a";
it will create an object and the value is stored in that and again if you are assigning value a="ty"
means it will create an another object store the value in that, if you want to understand clearly, check the has code
for the String
.
Only the reference is changing. First a
was referencing to the string "a", and later you changed it to "ty". The string "a" remains the same.
In your example, a
refers first to "a"
, and then to "ty"
. You're not mutating any String
instance; you're just changing which String
instance a
refers to. For example, this:
String a = "a";
String b = a; // b refers to the same String as a
a = "b"; // a now refers to a different instance
System.out.println(b);
prints "a", because we never mutate the String
instance that b
points to.
If some object bar
holds a reference to a mutable object foo
and encapsulates some of its state in mutable aspects of foo
's state, that will allow code which can change those aspects of foo
to change the corresponding aspects of bar
's state without actually touching bar
or even knowing of its existence. Generally, this means that objects which encapsulate their own state using mutable objects must ensure that no references to those objects are exposed to any code which might unexpectedly mutate them. By contrast, if bar
holds a reference to an object moo
and only uses immutable aspects of moo
other than identity to encapsulate its state, then bar
can freely expose moo
to outside code without worrying about anything the outside code might do to it.
Hope the below code would clarify your doubts :
public static void testString() {
String str = "Hello";
System.out.println("Before String Concat: "+str);
str.concat("World");
System.out.println("After String Concat: "+str);
StringBuffer sb = new StringBuffer("Hello");
System.out.println("Before StringBuffer Append: "+sb);
sb.append("World");
System.out.println("After StringBuffer Append: "+sb);
}
Before String Concat: Hello
After String Concat: Hello
Before StringBuffer Append: Hello
After StringBuffer Append: HelloWorld
Probably every answer provided above is right, but my answer is specific to use of hashCode()
method, to prove the points like, String... once created can't be modified and modifications will results in new value at different memory location.
public class ImmutabilityTest {
private String changingRef = "TEST_STRING";
public static void main(String a[]) {
ImmutabilityTest dn = new ImmutabilityTest();
System.out.println("ChangingRef for TEST_STRING OLD : "
+ dn.changingRef.hashCode());
dn.changingRef = "NEW_TEST_STRING";
System.out.println("ChangingRef for NEW_TEST_STRING : "
+ dn.changingRef.hashCode());
dn.changingRef = "TEST_STRING";
System.out.println("ChangingRef for TEST_STRING BACK : "
+ dn.changingRef.hashCode());
dn.changingRef = "NEW_TEST_STRING";
System.out.println("ChangingRef for NEW_TEST_STRING BACK : "
+ dn.changingRef.hashCode());
String str = new String("STRING1");
System.out.println("String Class STRING1 : " + str.hashCode());
str = new String("STRING2");
System.out.println("String Class STRING2 : " + str.hashCode());
str = new String("STRING1");
System.out.println("String Class STRING1 BACK : " + str.hashCode());
str = new String("STRING2");
System.out.println("String Class STRING2 BACK : " + str.hashCode());
}
}
OUTPUT
ChangingRef for TEST_STRING OLD : 247540830
ChangingRef for NEW_TEST_STRING : 970356767
ChangingRef for TEST_STRING BACK : 247540830
ChangingRef for NEW_TEST_STRING BACK : 970356767
String Class STRING1 : -1163776448
String Class STRING2 : -1163776447
String Class STRING1 BACK : -1163776448
String Class STRING2 BACK : -1163776447
String is immutable it means that,the content of the String Object can't be change, once it is created. If you want to modify the content then you can go for StringBuffer/StringBuilder instead of String. StringBuffer and StringBuilder are mutable classes.
참고URL : https://stackoverflow.com/questions/8798403/string-is-immutable-what-exactly-is-the-meaning
'programing' 카테고리의 다른 글
Android Studio 렌더링 문제 (0) | 2020.05.12 |
---|---|
Angular 2 베타 17 : 'map'속성이 'Observable'유형에 없습니다. (0) | 2020.05.12 |
Return 키를 누를 때 키보드를 숨기는 방법은 무엇입니까? (0) | 2020.05.12 |
Django로 이메일 템플릿 만들기 (0) | 2020.05.12 |
오류 : 접두사가 llvm 인 ABI의 NDK 도구 체인 폴더에 도구 체인이 없습니다. (0) | 2020.05.12 |