1. Java 문자열 대표 클래스
Java 에서 문자열을 다루는 대표적인 클래스는 String, StringBuilder, StringBuffer 가 있습니다.
3가지 클래스는 각자의 차이점이 존재합니다.
Java에서 String 객체는 한번 값이 할당되면 그 공간은 변하지 않습니다.
하지만 Stringbuilder나 StringBuffer 객체는 한번 값이 할당되더라도 한번 더 다른 값이 할당되면 할당된 공간이 변하는 특성을 갖고 있습니다.
String과 StringBuffer와 StringBuilder의 기본적인 차이는
String은 불변(Immutable)성,
StringBuffer와 StringBuilder는 가변(Mutable)성 이다.
직관적이어서 가장 많이 사용할 듯한 위의 예제에서 "hello" 값을 가지고 있던 String 클래스의 참조변수 str이 가리키는 곳에 저장된 "hello"에 "world" 문자열을 더해 "hello world"로 변경한 것으로 착각할 수 있습니다.
String str1 = "hello";
String str2 = new String("hello");
String str5 = str1 + " world";
System.out.println(str5); // [ hello world ]
System.out.println(str5==str1); //false
String str6 = str2 + " world";
System.out.println(str6); // [ hello world ]
System.out.println(str6==str2); //false

StringBuffer str7 = new StringBuffer("hello");
StringBuffer str8 = str7.append(" world");
System.out.println(str8); // [ hello world ]
System.out.println(str7==str8); //true
StringBuilder str9 = new StringBuilder("hello");
StringBuilder str10 = str9.append(" world");
System.out.println(str10); // [ hello world ]
System.out.println(str9==str10); //true

2. StringBuffer, StringBuilder
* 참고로 String도 불변성을 가지기때문에 마찬가지로 멀티쓰레드 환경에서의 안정성(thread-safe)을 가지고 있습니다.
3. 일반적인 사용용도
- String : 문자열 연산이 적고 멀티쓰레드 환경일 경우
- StringBuffer : 문자열 연산이 많고 멀티쓰레드 환경일 경우(동기화 지원)
- StringBuilder : 문자열 연산이 많고 단일쓰레드이거나 동기화를 고려하지 않아도 되는 경우
면접질문!
String, StringBuffer, StringBuilder 차이점이 무엇인가요?
- String : 객체의 값이 할당되면 할당된 공간이 변하지 않는 불변성인 특성이 있습니다.
* 불변성을 가지기때문에 마찬가지로 멀티쓰레드 환경에서의 안정성(thread-safe)을 가지고 있습니다. - StringBuilder, StringBuffer : 객체는 한번 값이 할당되더라도 한번 더 다른 값이 할당되면
할당된 공간이 변하는 가변성인 특성이 공통적으로 있으나 차이점이 존재합니다.
차이점으로는 동기화의 유무 입니다. - StringBuffer : 동기화를 지원하기 때문에 멀티쓰레드 환경에서 안전성을 가지고 있습니다.(Synchronized)
- StringBuilder : 동기화를 지원하지 않아 멀티쓰레드 환경보다는 단일 쓰레드 환경에서는
buffer보다 성능이 우수합니다.
* Synchronized란?
- 공유 데이터에 lock을 걸어 작업중이던 쓰레드가 마칠때까지 다른 쓰레드에게 제어권이 넘어가지 않게 보호한다.
- Synchronized 블럭이 끝나면 lock이 풀리고 다른 쓰레드도 접근 가능하게 된다.
- 교착상태(dead-lock)이 빠질 위험이 있으므로 주의한다.
※ String Constant Pool
String 변수에 값을 할당하는 방법은 2가지가 있습니다.
- Literal 변수를 대입하는 방법
- new 키워드를 사용하는 방법
위 두가지 방식을 사용하여 예시코드를 작성해보겠습니다.
String str1 = "hello";
String str2 = new String("hello");
String str3 = "hello";
String str4 = new String("hello");
System.out.println(str1==str2); //false
System.out.println(str1==str3); //true
System.out.println(str2==str4); //false
4개의 변수 모두 "hello"라는 문자열을 갖는데 3개의 주소비교(==)의 결과가 왜 다를까요?
그 이유는 String 타입 값 할당 방식에 따른 저장 방식이 다르기 때문입니다.
1. Literal 값으로 값을 할당하는 경우
String 을 Literal 값으로 할당하는 경우엔 Heap 메모리 영역안의 특별한 메모리 공간인 String constant pool 에 저장됩니다. String constant pool에 존재하는 Literal 값을 사용하게 된다면 새롭게 Literal 값을 만들어 String constant pool에 저장하는 것이 아닌, 현재 존재하는 값을 사용하게 됩니다.

위와 같은 이유로 System.out.println(str1==str3); 의 실행 결과가 true 가 나오게 되는 것입니다.
2. new 키워드로 값을 할당하는 경우
new 키워드를 통해 String 변수에 값을 할당하게 되면 일반적인 객체와 동일하게 Heap 영역에 동적으로 메모리 공간이 할당되게 됩니다.
마찬가지로 같은 문자열이더라도 new 키워드를 한번 더 사용하게 되면 같은 값이지만 다른 메모리 공간(Heap 영역 안)을 참조하게 됩니다.

위와 같은 이유로 System.out.println(str3==str4); 에서 false 를 출력하게 되는 것입니다.
그리고 System.out.println(str1==str2); 에서도 false 를 출력하는 것도 서로 상이한 메모리 공간을 참조하기 때문입니다.
- strA → Heap → String Constant Pool
- strB → Heap
'개발공부 > 개념정리' 카테고리의 다른 글
| 트래픽 급증으로 장애가 발생하면 어떻게 대응해야 하나요? [Scale Up vs Scale Out] (0) | 2022.06.22 |
|---|---|
| [JPA] Entity를 설계할때 주의점(N+1) (0) | 2022.06.21 |
| 데드락(DeadLock) (0) | 2022.06.19 |
| TDD(Test-driven development) (0) | 2022.06.18 |
| JPA(Java Persistence API) (0) | 2022.06.17 |