위 3가지의 차이점을 정리해보고자 한다.
앞서 백준 1212번을 풀며 시간초과가 발생하여 StringBuilder와 StringBuffer 사용에 대해 배운적이 있는데
String의 경우 값을 변경할 수 없어 기존 값을 버리고 새로운 객체를 생성해서 변경해야 하기 때문에 연산이 많은 경우 속도가 느려진다.
따라서 변경이 가능한 StringBuffer와 StringBuilder에 대해서 아래 게시글에서 언급한 적이 있다.
백준 1212번 inputmismatch, 시간 초과 해결하기 -> StringBuffer와 StringBuilder의 쓰임새
그러나 이 3가지에 대한 설명이 부족하기 때문에 이번에 정리해보고자 한다.
Primitive Type : byte, short, int, long, float, double, char, boolean, void
에 String은 없다. 즉 String은 클래스이기 때문에 객체를 구성해서 선언해야 한다.
String 클래스를 보면
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. **/
private final char[] value;
...
}
char 배열이 final로 선언되어져 있기 때문에
값을 변경할 수 없는 불변의 성격을 가지고 있다.
JVM(자바 가상 머신)에서는 따로 String Constant Pool이라는 독립적인 영역을 만든다.
이 공간에 문자열들을 Constant화 하여 공유하는데, 이 과정에서 데이터 캐싱이라는 것이 일 어나고, 그만큼 성능적 이득을 취할 수 있게 된다.
데이터가 불변하면, 멀티 스레드 환경에서 동기화 문제에서 안전한 결과를 낼 수 있다.
보안적으로 강화된다.
DB의 사용자 이름, 암호 등은 DB 연결을 수신하기 위해 문자열로 전달되는데, 번지 수의 문자열 값이 변경이 가능하다면 해커가 참조 값을 변경하여 문제를 일으킬 수 있음
값을 바꿀 수 없기 때문에 concat()이나 + 연산을 통해서 내용을 합치려고 할 때 기존의 객체에 내용이 수정되어져 붙여지는 것이 아니라 새로운 객체를 생성하고 기존의 객체는 가비지 컬렉터로 들어가게 된다.
그러나 반복적으로 문자열을 붙이면 Heap영역에 참조를 읽은 문자열 객체가 쌓이게 되어 속도가 느려지고 결국에는 메모리 초과가 발생한다.
문자열 리터럴 값을 바로 할당하는 경우
String a = "abc";
String Constant Pool 영역에 할당된다.
String이 한 번 사용되면 재사용될 확률이 높기 때문에 Heap 영역 내에 문자열 상수의 Pool을 유지하고,활용하는 것이다.
- Runtime Constant Pool
method영역 내에 있다.
각 데이터는 Runtime Constant Pool이라는 것을 가지게 되는데 이는 각 데이터의 Reference를 가지고 있어서 실제 물리적 메모리 위치를 참조할 때 사용
Constant Pool은 말 그래도 상수를 저장하는 공간이며 이외에도 필드나 메소드 등의 Reference 값들을 저장하고 있다. 이후, 실행중에 중복되는 정보가 필요할 때에 기존의 정보를 사용하도록 도와준다.
객체를 생성하는 new연산자를 이용하는 경우
String b = new String("abc");
Heap영역에 할당
따라서 굳이 객체를 새로 생성하면서(new String( )) 메모리를 낭비하기보단 리터럴로 생성해서 선언하자.
가변객체, 값을 변경할 수 있고 추가도 가능 -> 공간의 낭비도 없으며 속도고 매우 빠름
서로 제공하는 메소드는 서로 동일하나 차이는 동기화의 여부
StringBuffer는 각 메서드 별로 Synchronized Keyword가 존해하여 멀티쓰레드 환경에서도 동기화 지원, 단일 쓰레드 환경에서 사용가능하나 성능 측면에서 좋지 않음
그러나 StringBuilder는 동기화 보장하지 않음
클래스 | 특징 |
---|---|
String | 문자열 연산이 적고 멀티 쓰레드 |
StringBuffer | 문자열 연산이 많고 멀티 쓰레드 |
StringBuilder | 문자열 연산이 많고 단일 쓰레드 |
또한 StringBuffer와 StringBuilder는 equals함수를 오버라이딩하고 있지 않기 때문에 toString()을 이용하여 String으로 바꾼 후에 equals함수 이용이 가능하다.
String re_string = sb.reverse().toString();
if(re_string.equals(arr.get(i))) answer[i]="yes";