인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

hope님의 프로필 이미지
hope

작성한 질문수

기초 탄탄! 독하게 시작하는 Java - Part 2 : OOP와 JVM

JVM이 문자열 상수를 관리하는 구조

문자열 리터럴과 문자열 객체 관련해서 질문이 있습니다.

해결된 질문

작성

·

135

·

수정됨

0

안녕하세요!

강의를 듣던 도중에 의아한 부분이 있습니다.

 

8분 43초부터 들은 바에 의하면

  • 문자열 리터럴로 생성한 문자열은 (1) Runtime Constant Pool에 저장되고, (2) 사용되는 시점에 String Contant Pool에 복사된다.

  • new 키워드로 생성한 문자열 객체는 String Constant Pool에 저장된다. (이 내용은 10분 28초)

     

위 내용을 다음 사진처럼 표현해보았습니다.

스크린샷 2024-11-28 오후 10.46.11.png

 

 

여기서 한 가지 의아한 부분이 있는데요.

문자열 리터럴과 new 키워드로 생성한 문자열 객체 둘 다 String Contstant Pool에 저장된다면, 동일성 비교에서 true가 반환되지 않을까요??

스크린샷 2024-11-28 오후 10.53.01.png

 

 

그러나 실제로는 동일성 비교를 하면 false를 반환하게 됩니다.
제가 이해했던 바로는 문자열 리터럴은 String Constant Pool에 저장되고, new 키워드를 통한 문자열 객체는 Heap 영역에 저장되기 때문에 동일성 비교에서 false를 반환한다라고 생각했습니다.

스크린샷 2024-11-28 오후 10.56.21.png
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");

s1 == s2; // true
s1 == s3; // false

 

결론적으로 제가 궁금한 부분은..

new 키워드로 사용한 문자열 객체는 String Constant Pool이 아닌 단순히 JVM Heap 영역에 저장되는 것이 맞지 않는지 궁금합니다!

 

좋은 강의 감사합니다!!

(11분 08초에 natvie 오타가 있는 것 같습니다!)

 

답변 3

1

널널한 개발자님의 프로필 이미지
널널한 개발자
지식공유자

String constant pool은 Heap영역에 있습니다. 아마도 이 한 문장으로 답이 되지 않았을까 생각합니다. 😄

그리고 오타는 확인했습니다. 오타들이 제 눈에는 보이지 않는다는 점은 늘 미스테리 입니다. 제보 감사합니다. 😄

0

hope님의 프로필 이미지
hope
질문자

따라서 intern()의 경우에도 다음 흐름처럼 작동될 것이라 생각을 했습니다.

public class Main {
    public static void main(String[] args) {
        // 문자열 리터럴 s1는 JVM Heap 영역의 String Constant Pool에 저장된다.
        // s2는 문자열 리터럴에 존재하는 "hello" 문자열을 참조한다.
        String s1 = "hello";
        String s2 = "hello";
        System.out.println(s1.equals(s2)); // true
        System.out.println(s1 == s2); // true
        
        // 문자열 상수 풀에 "hello" 문자열이 존재하므로,
        // 문자열 상수 풀로부터 문자열 객체를 가져온다.
        System.out.println(s1.intern()); // hello
        System.out.println();

				// s3와 s4는 JVM Heap 영역에 저장된다.
        String s3 = new String("hello");
        String s4 = new String("hello");
        System.out.println(s3.equals(s4)); // true
        System.out.println(s3 == s4); // false, JVM Heap에 저장된 메모리 주소가 다르다.
        System.out.println();

        System.out.println(s1 == s3); // false, JVM Heap에 저장된 메모리 주소가 다르다.
        System.out.println(s1.equals(s3)); // true, 문자열 값이 일치한다.
    }
}
널널한 개발자님의 프로필 이미지
널널한 개발자
지식공유자

s1.intern()은 불필요합니다.

String s1 = "hello"; 구문에서 "hello"는 이미 런타임 상수 풀에 등록됐기 때문입니다. 참고하시기 바랍니다. 😄

0

안녕하세요, 인프런 AI 인턴입니다. hope님, “기초 탄탄! 독하게 시작하는 Java - Part 2 : OOP와 JVM” 강의와 관련된 질문에 대해 설명드리겠습니다.

자바에서 문자열 저장 및 비교하는 메커니즘에 대해 상당히 깊게 탐구하고 계신 것 같습니다. 이 부분은 많은 자바 개발자에게도 혼란을 줄 수 있는 주제입니다.

  1. 문자열 리터럴의 저장:
    자바에서 String s1 = "hello"; 와 같은 문자열 리터럴은 String Constant Pool에 저장됩니다. 이 풀은 JVM 메모리의 일부분으로 동일한 문자열 리터럴을 재사용하여 메모리를 절약합니다. 따라서, s1s2는 같은 “hello”라는 문자열 리터럴을 가리키고 있으므로 s1 == s2true를 반환합니다.

  2. new 키워드를 통한 문자열 생성:
    new String("hello")를 통해 생성된 문자열은 언제나 새롭게 힙 메모리에 저장됩니다. 이 경우 s3는 String Constant Pool에 있는 “hello”와는 다른, 힙 메모리에 새로이 생성된 “hello” 객체를 참조하게 됩니다. 따라서 s1 == s3false를 반환합니다. 이와 같은 동작은 두 객체가 서로 다른 메모리 위치를 참조하고 있기 때문입니다.

  3. 올바른 이해:
    자바의 문자열 비교에서 중요한 점은 ‘==’ 연산자가 객체 참조(메모리 주소)를 비교한다는 것이며, equals 메서드가 내용 자체를 비교한다는 것입니다. 만약 s1.equals(s3)를 수행한다면 true가 반환됩니다. 왜냐하면 두 문자열의 내용이 같기 때문입니다.

질문에서 제기된 내용에서는 new String()에 대한 이해가 핵심입니다. 이는 항상 새로운 객체를 생성하는 것이며, 이로 인해 문자열 리터럴과는 다른 위치에 저장된다는 점을 명확히 할 필요가 있습니다.

관련된 문제에 대해 더 깊게 이해하고 싶으시다면, 다음 유사한 질문과 답변을 참고하면 좋을 것입니다:

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

hope님의 프로필 이미지
hope

작성한 질문수

질문하기