Java String의 불변성이라는 주제를 일본 애니메이션 느낌으로 생성한 이미지

Java String의 불변성(immutability) 쉽게 이해하기

“Java String은 불변 객체이다.”라는 말 많이 들어보셨을 겁니다.” 저도 많이 들어봤고, 어렴풋이 알고는 있었지만, 남들에게 설명할 정도로 알고 있지는 못한 것 같아서 쉽게 이해할 수 있도록 정리해 봤습니다.

Java String의 불변성이라는 주제를 일본 애니메이션 느낌으로 생성한 이미지

Java String의 불변성(immutability) 이란?

Java String의 불변성을 잘 이해하지 못한 사람이 아래의 코드를 보면 이런 생각이 들 것입니다.
‘String 변수의 값이 잘만 바뀌고 있는데 뭐가 불변이라는 거지?’

String str = "simple play";
str = "simsimplay.com";

아래의 코드도 한 번 봐주세요.

String str = "simple play";
System.out.println("초기 주소 값: " + System.identityHashCode(str));

str = "simsimplay.com";
System.out.println("변경 후 주소 값: " + System.identityHashCode(str));

// 출력 결과:
// 초기 주소 값: 1650967483
// 변경 후 주소 값: 109961541

똑같은 str이라는 이름의 변수이지만 내부적인 주소 값은 문자열이 변경되면서 바뀌었습니다.

Java String의 동작 원리

  1. “simple play”라는 값을 가진 String 객체가 내부적으로 생성된다.
  2. String str 변수는 “simple play”라는 값을 가진 String 객체의 주소 값을 참조한다.
  3. “simsimplay.com”이라는 값을 가진 String 객체가 내부적으로 생성된다.
  4. String str 변수는 “simsimplay.com”이라는 값을 가진 String 객체의 주소 값을 참조한다.

문자열이 변할 때마다 String 객체가 내부적으로 새로 생성되고, 원래 있던 String 객체는 이전값을 가지고 계속 남아있기 때문에 “Java의 String은 불변하다”라고 합니다. 사용되지 않는 String 객체는 가비지컬렉터의 대상이 서 제거될 수도 있기 때문에 언젠가는 사라지긴 합니다.

Java String 비교 시 == 대신 equals()를 써야 하는 이유

Java String의 불변성은 아주 중요한 개념입니다. 이걸 잘 모르더라도 우리는 이미 이 String의 불변성을 고려해서 코딩하고 있었습니다. 그게 무슨 말이냐 하면 Java에서 String이 같은지 비교할 때 ==연산자로 비교하지 않고, equals() 메서드로 비교해야 한다는 것은 누구나 알고 있을 텐데요. 이렇게 하는 이유가 바로 Java String의 불변성 때문입니다.

이 부분에 대해서도 좀 더 자세하게 알아보려면 문자열 상수 풀(Java Constant Pool)이라는 걸 알아야 합니다.

문자열 상수 풀(String Constant Pool)

Java는 메모리 효율을 위해 문자열 리터럴(“…”로 생성한 문자열)을 문자열 상수 풀(String Constant Pool)이라는 특별한 공간에 저장하고 재사용합니다.

String s1 = "simsimplay"; // "simsimplay"가 String Constant Pool에 없으면 새로 만들고 s1은 그 주소를 가리킴
String s2 = "simsimplay"; // String Constant Pool에 이미 "simsimplay"가 있으므로 새로 만들지 않고 기존 주소를 가리킴

String s3 = new String("simsimplay"); // new 키워드는 항상 새로운 객체를 생성
String s4 = "simsim" + "play"; // 컴파일 시 "simsimplay"로 최적화되기 때문에 s1과 동일한 주소를 가리킴

System.out.println("s1 == s2 : " + (s1 == s2)); // true, 같은 주소를 가리킴
System.out.println("s1 == s3 : " + (s1 == s3)); // false, 다른 주소를 가리킴
System.out.println("s1.equals(s3) : " + s1.equals(s3)); // true, 내용은 같음

System.out.println("s1 == s4 : " + (s1 == s4)); // true, 같은 주소를 가리킴
System.out.println("s1.equals(s4) : " + s1.equals(s4)); // true, 내용 같음

위 예제를 보시면 ==가 아닌 equals() 메서드로 문자열을 비교해야 하는 이유를 확실히 알 수 있습니다.

Java 공식 문서 참조

Java 공식 문서에 보면 Java String의 불변성에 대해서 잘 나와 있습니다. “모든 문자열은 String 클래스의 인스턴스로 구현되어 있고, 상수이며, 생성된 후에는 값을 변경할 수 없다”라는 내용이 상단 부분에 명확하게 나와 있습니다. String은 확실히 불변 객체입니다.

https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/String.html

마치며

이 글에 나온 정도만 이해하면 Java String의 불변성에 대해서 다른 사람에게 자신있게 설명할 수 있을 정도는 될 것 같습니다. 어렴풋이 알고 있지만 남들에게 설명할 자신이 없는 내용들을 다시 한 번 정리하는 것은 정말 중요한 습관인 것 같네요. AI로 공부하다 보니 Java가 불변으로 설계된 이유도 자세하게 나오고, String을 구현한 Java 내부 소스 코드에서 Java String의 불변성을 어떻게 구현했는지도 나오던데 그런 것 까지 다루는 것 보다는 딱 이 정도만 알고 일단 끊는 것도 괜찮은 것 같아서 멈췄습니다. 여유 있으면 그런 부분들도 공부해보시면 좋을 것 같네요.

잘못된 부분이나 어렵게 설명된 부분이 있으면 댓글로 남겨주세요. 아니면 훨씬 쉽게 설명된 글이 있으면 글의 주소도 댓글로 공유해주세요. 부족한 글 끝까지 읽어주셔서 감사합니다.

Similar Posts

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다