Computer >> 컴퓨터 >  >> 프로그래밍 >> Java

Java String 클래스 intern() 메서드, 언제 어떻게 사용해야 할까?

Java에서 String 클래스의 intern() 메서드문자열 중복 문제(string duplication problem)를 처리할 때 활용할 수 있습니다. intern()을 사용하면 내용이 같은 중복 문자열 인스턴스가 불필요하게 차지하는 메모리를 크게 절약할 수 있습니다.

문자열 중복이란?

어떤 문자열이 다른 문자열과 동일한 내용을 가지면서도 서로 다른 메모리 위치에 저장되어 있다면, 그 문자열은 '중복'되었다고 말할 수 있습니다. 내용은 같은데 객체가 여러 개 존재하는 상황이죠.

JVM의 문자열 풀(String Pool) 동작 방식

JVM은 성능 향상을 위해 문자열 리터럴을 위한 별도의 힙 영역(문자열 풀)을 유지 관리합니다. 문자열 리터럴을 선언하면 해당 값이 이 풀(pool)에 저장되고, 이후 다른 변수에 동일한 리터럴 값을 할당하면 새 객체를 생성하지 않고 풀에 있는 기존 객체를 재사용합니다.

그러나 문자열을 new 생성자로 선언하면, 풀에 동일한 리터럴이 이미 존재하더라도 새로운 객체가 무조건 생성됩니다. 이런 낭비를 막고 JVM이 풀에 있는 리터럴을 강제로 참조하도록 만들 때 바로 intern() 메서드를 사용하는 것입니다.

참고로 Java는 기본적으로 모든 문자열 리터럴을 자동으로 intern 처리합니다. 따라서 new String()으로 생성된 문자열에 intern()을 호출하면, == 연산자를 통한 참조 비교가 가능해집니다.

예제 코드

public class StringInternClassTest {
    public static void main(String[] args) {
        String s1 = "Tutorix";
        String s2 = "Tutorix";
        String s3 = new String("Tutorix");
        final String s4 = s3.intern();
        String s5 = "?Tutorix".substring(1);
        String s6 = s5.intern();
        System.out.println(s1 == s2);
        System.out.println(s2 == s3);
        System.out.println(s3 == s4);
        System.out.println(s1 == s3);
        System.out.println(s1 == s4);
        System.out.println(s1 == s5);
        System.out.println(s1 == s6);
        System.out.println(s1.equals(s2));
        System.out.println(s2.equals(s3));
        System.out.println(s3.equals(s4));
        System.out.println(s1.equals(s4));
        System.out.println(s1.equals(s3));
    }
}

실행 결과

true
false
false
false
true
false
true
true
true
true
true
true

결과 분석

  • s1 == s2 → true: 두 변수 모두 리터럴이므로 문자열 풀의 같은 객체를 참조합니다.
  • s2 == s3 → false: s3는 new로 생성된 별도의 힙 객체입니다.
  • s3 == s4 → false: s4는 intern()을 통해 풀의 객체를 가리키므로 s3와는 다릅니다.
  • s1 == s4 → true: intern() 덕분에 s4도 풀의 리터럴 객체를 참조하게 됩니다.
  • s1 == s5 → false: substring()은 새로운 문자열 객체를 생성합니다.
  • s1 == s6 → true: s5.intern() 결과가 풀의 리터럴과 동일한 객체를 가리킵니다.

반면 equals() 메서드는 객체의 참조 위치와 상관없이 내용 자체를 비교하기 때문에 모든 경우 true를 반환합니다. 결국 intern()은 문자열의 내용 비교가 아닌 참조(메모리) 최적화가 필요할 때 유용하게 사용할 수 있습니다.