https://www.baeldung.com/java-string-constant-pool-heap-stack 의 내용을 참고했습니다
Java를 쓰시는 분들이라면, 문자열 비교를 위해 == 연산자 사용하면 안된다는 것을 알고 계실겁니다.
Java의 String은 원시형이 아닌 객체이기 때문에 객체 참조 주소(reference)를 비교하는 == 연산자로 문자열을 비교하면, 원하는 결과를 얻을 수 없을 가능성이 높습니다.
그런데 다음과 같은 코드에서 == 연산자를 사용하면 어떻게 될까요?
public class Main {
public static void main(String[] args) {
String cat1 = "cat";
String cat2 = "cat";
System.out.println(cat1 == cat2);
}
}
위 내용에 따르면 같은 내용의 문자열이더라도 참조하는 주소가 다르기 때문에 false가 출력되어야 할 것입니다.
하지만 실행시켜 보면, 결과는 true로 출력됩니다.
JVM은 Stack에 객체의 참조 주소를 쌓고, 실제 값은 Heap에 저장합니다. 때문에 String의 실제 값은 Heap에 저장됩니다.
위 그림에서 보시는 것과 같이, JVM은 Heap에서 String (Constant) Pool을 운영합니다.
String Pool은 내부적으로 HashMap 자료구조를 통해 운영됩니다. Key는 문자열의 hashcode, value는 해당 문자열의 참조 주소(일 것이라고 생각합니다. 같은 내용의 문자열이 같은 주소를 향하게 해야 하니까, 당연히 이 구조이지 않을까 싶습니다)
이 때문에, 위 예시에서 cat1, cat2가 참조하는 주소가 같은 나오는 것입니다. 다음과 같은 예시에서도 결과는 같습니다.
public class Main {
public static void main(String[] args) {
String cat = "cat";
catString(cat);
}
public static void catString(String catArg) {
System.out.println(catArg == "cat");
}
}
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String cat = "cat";
String input = sc.next();
System.out.println(cat == input);
}
}
JVM이 String Pool을 운영하는 단계는 컴파일 단계까지
라는 것을 확인할 수 있습니다.
맨 위에서 공유드린 링크의 원문에, String Constant Pool이 Applicatoin-level pool이라는 말이 볼드체로 서술되어 있습니다.
Applicatoin-level pool이라는 것은,
등의 단위가 아닌, 말 그대로 Java 어플리케이션 레벨에서 동작하는 Pool이라는 뜻입니다.
즉, 다른 클래스나 다른 패키지의 문자열이라도 그 내용이 같다면 같은 참조 주소값을 가진다는 것입니다. 다음 예시를 통해 확인해보겠습니다.
public class Cat {
String catString;
public Cat(String catString) {
this.catString = catString;
}
}
public class Main {
public static void main(String[] args) {
String cat = "cat";
Cat catClass = new Cat("cat");
System.out.println(cat == catClass.catString);
}
}
짜잔, true가 출력되었습니다!