카테고리 없음

자바 공부#1_05. String

코딩연습중 2025. 3. 30. 15:27

String

String은 문자열 데이터를 저장하기 위해 사용되는 참조형의 데이터타입이다.

String 타입의 객체는 heap 영역에 메모리가 할당되며, hash table을 통해 heap 영역에 저장된 문자열 데이터와 매핑된다.

String은 다른 자료형과 다르게 특수한 성질을 가진다.

1. String의 특성 - Immutable(불변)

String 객체는 한 번 생성되면 그 값을 변경할 수 없다.
즉, 어떤 연산을 통해 문자열을 수정하려고 하면, 기존 객체가 바뀌는 것이 아니라 새로운 객체가 생성된다.

이러한 특성은 다음과 같은 장점을 가진다:

  • 보안성: 문자열이 수정되지 않기 때문에 URL, 패스워드, 쿼리문 등 민감한 정보를 안전하게 다룰 수 있다.
  • 스레드 안정성: 값이 바뀌지 않으므로 멀티스레드 환경에서도 안전하게 공유할 수 있다.
  • String Pool 재사용 최적화: 변경 불가능한 특성 덕분에 동일한 리터럴을 공유하여 메모리를 절약할 수 있다.

[출처: https://deveric.tistory.com/123 ]

 

 

근데 String이 참조형이라면 어떻게 String a = ""; 이런 식으로 String 객체를 만들 수 있는 것일까?

String은 "리터럴"을 지원하는 특별한 클래스이기 때문!
자바에서는 문자열 리터럴 "hello" 을 만나면 JVM이 String 객체로 자동 생성

 

그럼 자바에서 String 객체를 만드는 방법에 뭐가 있을까?

2. new String() vs 리터럴

1) 리터럴 방식

String a = "hello";
String b = "hello";

System.out.println(a == b); // ✅ true → 같은 객체 (String constant pool 공유)
  • 문자열 리터럴은 JVM이 String constant pool에서 관리
  • 동일한 값이면 재사용된다 → 메모리 절약

2) new 연산자 사용

String c = new String("hello");
String d = new String("hello");

System.out.println(c == d); // ❌ false → 서로 다른 객체
System.out.println(c.equals(d)); // ✅ true → 값은 같음
  • new 연산자는 항상 heap 영역에 새로운 객체 생성
  • 값은 같더라도 객체 참조가 다르므로 == 비교는 false
  • equals()를 사용해야 값 비교가 된다

 

결론

  • 문자열을 비교할 때는 반드시 equals()를 사용하는 게 좋다
  • 문자열이 자주 재사용되는 경우에는 리터럴 방식을 사용하는 것이 성능적으로 유리하다
  • immutable 특성을 잘 이해하면 StringBuilder, StringBuffer의 필요성도 자연스럽게 보이게 된다

 

3. intern() 메서드

Java에서 문자열을 리터럴로 선언할 경우, 내부에서 String.intern() 메서드가 자동으로 호출된다.

이 메서드는 해당 문자열이 String Constant Pool에 존재하는지 먼저 확인하고,

  • 존재하면 → 기존의 상수 풀 객체 레퍼런스를 반환
  • 존재하지 않으면 → 상수 풀에 새로 저장한 후 그 레퍼런스를 반환한다.
String a = new String("hello");
String b = "hello";

System.out.println(a == b);              // false
System.out.println(a.intern() == b);     // true

intern()을 사용하면 new 연산자로 생성한 문자열도 리터럴과 같은 참조를 가질 수 있다.


⚠️ intern() 사용 시 주의점

  • intern()은 문자열을 강제로 상수 풀에 등록하기 때문에,
    동적인 문자열(예: 사용자 입력, 외부 API 응답 등)에 반복적으로 사용하면
    String Constant Pool의 크기가 커지며 메모리 사용량이 증가할 수 있다.
  • String Constant Pool은 일반적으로 GC의 대상이 되지 않고 애플리케이션 종료 시까지 유지되기 때문에,
    과도하게 사용하면 메모리 누수(leak)로 이어질 가능성이 있다.
  • 또한, intern() 메서드는 비용이 크고 상대적으로 느린 편이기 때문에,
    성능이 중요한 상황에서는 사용을 지양하는 것이 좋다.

intern()은 특정 상황에서 문자열 비교 최적화에 도움이 될 수 있지만, 잘못 사용하면 메모리 과다 사용 및 성능 저하의 원인이 되기 때문에 제한된 상황에서만 사용하는 것이 좋다.

 

 

참고:

https://readystory.tistory.com/139

https://inpa.tistory.com/entry/JAVA-%E2%98%95-String-%ED%83%80%EC%9E%85-%ED%95%9C-%EB%88%88%EC%97%90-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-String-Pool-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%B9%84%EA%B5%90

https://deveric.tistory.com/123