2013-09-10 5 views
1

나는 약간 혼란 스러워요 분명 여기에 뭔가 빠진 :자바 문자열 "상수"혼란

내가 읽어 java.lang.String의의 "상수이므로 만든 후에 값을 변경할 수 없습니다."

하지만 난 다음 코드를 작성하는 경우 :

String line; 
line = "Test1"; 
System.out.println(line); 
line = "Test2";  
System.out.println(line); 

터미널 출력 : 내가 값을 설정 한 다음 나중에 문자열에 대한 다른 값을 설정할 수 있어요 나타납니다

Test1 
Test2 

합니다.

난이 방법을 시도하는 경우에는 차이 :

String line2 = "Test3"; 
System.out.println(line2); 
line2 = "Test4"; 
System.out.println(line2); 

나는 여전히 처음에 설정 한 후 값을 설정할 수 있어요.

여기서 내가 어디로 잘못 갔습니까?

감사합니다.

+8

예에서는 값을 수정하지 않고 참조를 수정합니다. –

+0

http://en.wikipedia.org/wiki/Immutable_object – Habib

+0

모든 답장을 보내 주셔서 감사합니다. 레퍼런스가 무엇이 바뀌 었는지에 대한 정확한 인식. 이것은 어떤 객체를위한 것인가 아니면 원시 타입에도 역시 적용 되는가? – Xerphiel

답변

2

는 의견

String line; // declares a variable of type String 
line = "Test1"; // creates a new String object with value "Test1" and makes line reference it 
System.out.println(line); // don't care 
line = "Test2"; // creates a new String object with value "Test2" and makes line reference it 

사람들은 두 개의 서로 다른 객체를 참조하십시오.

String 때문에, 그 값이 자바로 할 수 없습니다이

line = "Test1"; 
line[4] = "2"; 
System.out.println(line); // printing Test2 

같은 일을 할 것입니다 변경은 불변의 인스턴스를 생성합니다.

참조 할당과 개체 값 변경 사이에는 차이가 있습니다.

+0

주셔서 감사합니다. 이것은 객체 기반 변수에만 적용됩니까? 원시 유형은 무엇입니까? – Xerphiel

+0

@Xerphiel 프리미티브에 대한 것은 프로그래밍 언어의 원자 (쿼크)라는 점입니다. 더 이상 문제를 해결할 수 없으므로 가치를 바꾸는 것에 대해 이야기하는 것이 타당하지 않습니다. Object는 여러 프리미티브 필드와 다른 참조 필드로 구성 될 수 있습니다. 개체의 값을 변경함으로써 해당 개체를 변경할 수 있습니다. –

3

JVM Test1 및 Test2에서 힙 메모리에는 두 개의 문자열 값이 생성되고 할당 된 공간이 있습니다. 현재 수행중인 작업은 참조 주소를 변경하는 것입니다. 다음은 코드 문에 대한 바이트 코드입니다. lcd이 다른 문자열 참조를 얻는 것을 볼 수 있듯이 opcode에 ldc에 집중하십시오.

public class JavaConstant extends java.lang.Object { 
    public JavaConstant(); 
    Code: 
     0: aload_0 
     1: invokespecial #8     // Method java/lang/Object."<init>":()V 
     4: return 

    public static void main(java.lang.String[]); 
    Code: 
     0: ldc   #16     // String Test1 
     2: astore_1 
     3: getstatic  #18     // Field java/lang/System.out:Ljava/io/PrintStream; 
     6: aload_1 
     7: invokevirtual #24     // Method java/io/PrintStream.println:(Ljava/lang/String 
;)V 
     10: ldc   #30     // String Test2 
     12: astore_1 
     13: getstatic  #18     // Field java/lang/System.out:Ljava/io/PrintStream; 
     16: aload_1 
     17: invokevirtual #24     // Method java/io/PrintStream.println:(Ljava/lang/String 
;)V 
     20: return 
} 
+0

나는 당신이 들어갈 세부 사항을 좋아하지만 나는 100 %를 이해하지 못한다. 당신은 ldc에 대해 자세히 설명해 주시겠습니까? 감사합니다. – Xerphiel

+0

여러 문장으로 설명하여 JVM 작동 원리를 쉽게 이해할 수 없습니다. Pls는 원하는 것을 묻는 것보다이 기사를 나중에 읽었다. –

+0

ldc는 한 단어 상수를 피연산자 스택에 푸시합니다. ldc는 푸시 할 값인 단일 매개 변수 을 사용합니다. ldc를 사용하여 다음 Java 유형을 푸시 할 수 있습니다. int float 문자열 –

4

문자열은 변경 불가능하며 값은 변경할 수 없습니다. 사실입니다.

하지만 코드에서 참조로 작업하고 있습니다.

String line; //allocate variable 
line = "Test1"; //assign to variable value "Test1" 
System.out.println(line); 
line = "Test2"; //assign to variable value "Test2" 

변경할 수없는 것은 문자열 자체가 가변 참조가 아닙니다.

세부 JLS 15.26

이 개체 유형과 원시에 적용됩니다.

+0

고마워요, 이것은 객체 기반 변수에만 적용됩니까, 원시 타입은 어떻습니까? – Xerphiel

1

문자열을 변경할 수 없습니다. String 값은 변경할 수 없습니다. 새 String 객체를 만들거나 String 풀에서 참조합니다.

String line;     // line is at Location A 
line = "Test1";    // Location A --> "Test1" 
System.out.println(line); // Prints Test1 
line = "Test2";    // Location A --> "Test2" --> Reference to Test1 is lost 
System.out.println(line); // Prints Test2 
1

모든 답변은 위의 모든 올바른 문자열은 불변이며, 개체를 편집 할 수 없습니다, 다른 손에 참조는 당신이 그들을 제거하거나 편집 할 수 있습니다.

가비지 수집기는 더 이상 사용할 수 없으므로 참조가없는 모든 개체를 제거합니다.

자바에는 힙과 스택이라는 2 개의 메모리가 있습니다. 변수가 스택에있는 동안 객체는 힙에 살고 있습니다.

당신이

String test1="Test1" 

TEST1은 살전 스택에 거주하고

그러나 "Test1을"살고는 스택에없는

을 변경할 수 있습니다 당신이 그것을 편집 할 수 있습니다 만들 때. 이

String test1, test2; 

test1 = test2 = "MyString" 

당신이 = TEST1 변경하는 경우는 "안녕하세요"TEST2은 영향을 어느 문자열 자체되지 않습니다. 반면에이

Person person1, person2; 
person1 = person2 = new Person("Nickname") 

person1.rename("My new name"); 

는 사람의 이름 (힙에 거주하고있는 객체)

그것은 스택 참조 모두 PERSON1 및 PERSON2을 변경하지 않았다을 편집하는 것입니다 이 변화에 의해 "영향을받을"것입니다.