package com.company;
public class Main {
public static void main(String[] args) {
String str1 = "abc";
String str2 = "abc";
String str3 = new String("abc");
System.out.print("str1==str2 : ");
System.out.println(str1==str2);
//true
System.out.print("str1.equals(str2) : ");
System.out.println(str1.equals(str2));
//true
System.out.print("str1==str3 : ");
System.out.println(str1==str3);
//flase
System.out.print("str1.equals.(str3) : ");
System.out.println(str1.equals(str3));
//true
str3 = str3.intern();
System.out.print("after str3.inter() str1==str3 : ");
System.out.println(str1==str3);
//true
System.out.println(""+str1==str2); // 앞에 "" 만 넣었는데 왜 결과가 flase가 될까
}
}
문자열 리터럴이 메모리에서 저장되는 방법
str1은 "abc"라고 하는 리터럴 문자열을 str1 이라는 변수에 대입시킨 것이다. JVM 스택에 생성된 str1이라는 변수는 힙 메모리에 생성된 객체를 참조하고, 이 객체는 메모리의 메소드 영역에 있는 상수풀(String Constant Pool)을 참조한다. 즉 new 라는 객체 생성 연산자를 사용하지 않아도 내부적으로는 객체를 생성한다는 의미이다. 하지만String str1 = "abc"; 에서 "abc" 는 객체에 생성된 것이 아닌 상수풀을 참조하는 것이다.
문자열 리터럴
문자 리터럴은 상수의 한 종류로서 변하지 않는 (immutable) 중요한 특성이 있다. 덕분에 다양한 변수가 있더라도 동일한 문자열을 지닌다면 동일한 객체와 상수풀을 참조한다. 그렇기 때문에 같은 문자열인 str2 또한 상수풀에 생성된 동일한 abc 를 참조하고 있는 것이다. 즉 str1과 str2는 같은 상수풀을 참조하고 있는 것이다.
문자열 리터럴은 내부적으로 intern()이라는 메소드를 사용하는데, intern()메소드는 해당 문자열이 상수풀에 이미 있는 경우에는 그 문자열의 주소값을 반환하고, 없다면 새로 집어넣고 그 주소값을 반환한다. 이러한 원리를 통해 문자열 리터럴이 같은 객체와 상수풀을 참조하는 것이다.
new 연산자를 이용한 문자열이 메모리에 저장되는 방법
String str3 = new String("abc");
위와 같이 new를 이용한 객체 생성 방법은 매번 new 라는 연산자를 이용하여 새롭게 힙 영역에 만들어지므로 str1, str2와 같은 객체라고 할 수 없다.
str3 = str3.intern();
이러한 경우는 str3 이라는 객체가 만든 문자열을 상수풀에 등록하도록 intern() 메소드를 호출한 것이다. 이미 상수풀에는 "abc" 이 존재하기 때문에 원래 상수풀의 주소값을 반환하게 된다. 그래서 결국 str3 == str1 은 true가 된다.
String의 문자열 생성 방식에는 2가지 방법이 있다.
문자열 리터럴이 메모리에서 저장되는 방법
str1은 "abc"라고 하는 리터럴 문자열을 str1 이라는 변수에 대입시킨 것이다. JVM 스택에 생성된 str1이라는 변수는 힙 메모리에 생성된 객체를 참조하고, 이 객체는 메모리의 메소드 영역에 있는 상수풀(String Constant Pool)을 참조한다. 즉 new 라는 객체 생성 연산자를 사용하지 않아도 내부적으로는 객체를 생성한다는 의미이다. 하지만
String str1 = "abc";
에서"abc"
는 객체에 생성된 것이 아닌 상수풀을 참조하는 것이다.문자열 리터럴
문자 리터럴은 상수의 한 종류로서 변하지 않는 (immutable) 중요한 특성이 있다. 덕분에 다양한 변수가 있더라도 동일한 문자열을 지닌다면 동일한 객체와 상수풀을 참조한다. 그렇기 때문에 같은 문자열인 str2 또한 상수풀에 생성된 동일한
abc
를 참조하고 있는 것이다. 즉 str1과 str2는 같은 상수풀을 참조하고 있는 것이다.문자열 리터럴은 내부적으로 intern()이라는 메소드를 사용하는데, intern()메소드는 해당 문자열이 상수풀에 이미 있는 경우에는 그 문자열의 주소값을 반환하고, 없다면 새로 집어넣고 그 주소값을 반환한다. 이러한 원리를 통해 문자열 리터럴이 같은 객체와 상수풀을 참조하는 것이다.
new 연산자를 이용한 문자열이 메모리에 저장되는 방법
위와 같이 new를 이용한 객체 생성 방법은 매번 new 라는 연산자를 이용하여 새롭게 힙 영역에 만들어지므로 str1, str2와 같은 객체라고 할 수 없다.
이러한 경우는 str3 이라는 객체가 만든 문자열을 상수풀에 등록하도록 intern() 메소드를 호출한 것이다. 이미 상수풀에는
"abc"
이 존재하기 때문에 원래 상수풀의 주소값을 반환하게 된다. 그래서 결국str3 == str1
은 true가 된다.