[Java] String Constant Pool

mincho920·2022년 4월 7일
0

Java

목록 보기
7/8

https://www.baeldung.com/java-string-constant-pool-heap-stack 의 내용을 참고했습니다

0. Java Constant Pool

  • Java는 Heap에서 원시형 자료들에 대한 상수 풀을 운영합니다.
  • 이는 메모리 절약을 위함으로, 컴파일 단계에서 새로 선언된 상수와 동일한 값이 상수 풀에 있다면 Heap의 메모리를 더 사용하지 않고 기존에 사용하는 값의 참조 주소를 리턴합니다.

1. Java의 String은 원시형이 아니다

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로 출력됩니다.


2. String Constant Pool

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);
    }

}

  • Scanner를 통한 input은 런타임에서 동작합니다
  • 위와 같이 런타임에서의 문자열까지는 String Pool을 통한 참조 주소 일치가 적용되지 않은 것을 볼 때,

    JVM이 String Pool을 운영하는 단계는 컴파일 단계까지

라는 것을 확인할 수 있습니다.


3. Application Level 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가 출력되었습니다!

profile
Java/Spring Back-End Developer

0개의 댓글