본문 바로가기
Programming/Languages (Java, etc)

[JAVA] String 데이터 타입, String pool

by kghworks 2022. 1. 28.

목차

  • String 객체
  • String Interning
  • literal vs new String()
  • 참조

String 객체

String 데이터 타입은 기본형이 아니라 객체입니다. 따라서 Stack에 값이 바로 저장되지 않고 Heap영역에 저장되고, 그 주소 값을 참조하는 변수가 stack에 쌓이게 됩니다. (아래 그림 참고)

 

Heap에 저장할 때는 Heap 안의 String pool에 저장합니다.

String 객체의 메모리 구조


String Interning

String 객체가 리터럴로 할당된다면 Heap 영역의 String Constants Pool에 저장되어 관리합니다. 기본적으로 pool안의 객체는 불변성 (Immutability)을 띄며 이 얘기는 값의 수정이 없고, 같은 값이 선언된다면 같은 객체를 참조하도록 한다는 의미입니다. 

 

 리터럴로 Stirng 값을 할당하면 JVM은 String pool에서 같은 값이 있는지 검사합니다. 그리고 같은 값이 있다면 새로운 공간 할당 없이 해당 객체를 참조하도록 합니다. 이런 방식으로 String Constants Pool에 저장하고 관리하는 것을 String Interning이라고 합니다.

 

String host1 = "localhost";
String host2 = "localhost";

 

위와 같이 리터럴로 host1을 선언할 때 리터럴로 했다면 내부적으로 intern() 이 실행됩니다.

같은 리터럴 값이 있는지 String pool을 검사하는 것입니다. host2를 선언할 때 한번 더 intern 이 실행되겠죠. 그리고 host1이 참조 주소 값과 host2가 참조 주소 값은 같습니다.

 

System.out.println(host1 == host2); //true

* == 은 참조 주소 값을 비교하고, equals()는 실제 값 (value)를 비교합니다.


literal vs new String()

String의 값을 초기화할 때는 new 연산자를 이용하는 방법도 있습니다.

이때는 String pool이 아닌 외부 영역 (Heap)에 할당이 되고, 값이 같을 지라도 interning 영향 범위가 아니기에 계속 새로운 객체를 만들어 냅니다.

 

리터럴 방식과 함께 조금 더 복잡한 예시입니다.

 

String a = "aaa";
String b = "aaa";
String c = new String("aaa");
String d = new String("aaa");

// == 은 참조 주소값 비교
System.out.println(a == b); //true
System.out.println(a == c); //false
System.out.println(c == d); //false

// .equals() 는 실제 값 비교
System.out.println(a.equals(b)); //true
System.out.println(a.equals(c)); //true
System.out.println(c.equals(d)); //true


참조

https://www.baeldung.com/java-string-pool

 

댓글