본문 바로가기

Java

String과 StringBuilder

String

string은 불변이다.

String str = "abc";
str = "def";

가 가능한데 왜 불변일까.

 

여기서 중요한 점은, String은 기본타입이 아닌 참조타입이라는 점이다.

String 변수형의 첫 글자가 대문자임에서도 나타나듯이, 클래스이다.

 

String 객체는 stack영역에 직접 값을 저장하는 int, char등과 달리

Heap영역의 String constant pool이라는 곳에서 따로 관리된다.

 

 

드래그

List<int>가 안되고 List<Integer>은 되는 이유는,  wrapper는 클래스이기 때문에 힙영역에서 관리된다.

collection 역시 힙 영역에서 관리되기 때문에, List<int>는 힙영역에서 스택영역을 참조하는 구조라 말이 안된다.

(방금 생각한 내용)

 

int num = 10;
num = 20;

기본 타입인 int는 값 자체가 스택 메모리에 저장된다.

이후 값이 바뀌면 10이라는 것을 20으로 바꾼다.

따라서 가변이라 할 수 있다.

 

하지만 String은 참조 타입이기 때문에 Heap영역의 String constant pool에 값을 가지고 그 주소를 stack영역에서 가지게 된다.

값이 "abc"에서 "def"로 변경되면, 새로운 "def"를 만들고 그 주소값을 참조하게 된다.

따라서 str에 새로운 값을 넣는다 해도 "abc"의 값이 "def"로 바뀌는 게 아니다라는 말이다.

"abc"값은 그대로 유지된다.

따라서 불변 이라는 것이다.

 

 

이렇게 String을 불변으로 관리하면 아래의 이점을 가질 수 있다.

 

1. Heap영역의 메모리를 절약할 수 있다. 같은 값을 가지는 String들에 대해 같은 메모리를 참조하게 할 수 있기 때문이다.

 

2. 멀티 쓰레딩 환경에서 동기화 문제에 대해 안전하다.

 

3. JAVA는 String의 hashchode를 생성할 때 캐싱한다. 따라서 쓰일 때 마다 hashcode를 계산하지 않아도 된다.

hashcode를 키값으로 사용하는 HashMap에서 좋은 성능을 발휘한다.

 

4. String이 불변이 아니라면 String으로 관리되는 여러 데이터에 대해 보안상의 문제가 생길 수 도 있다.

 

 

 

 

여기서 주의할 점은 String을 생성하는 방법은 두가지가 있는데,

String str1 = "apple";
String str2 = new String("apple");

 

위의 두 변수의 결과는 동일하지만 저장되는 공간은 엄연히 다르다.

String literal로 생성하면 문자열은 힙영역의 String Pool에 저장되어 만약 문자열이 같으면 참조를 공유할 수 있다. (같은 객체이다)

new 연산자로 생성하면 문자열은 힙영역에 저장되어 문자열이 같더라도 새로운 주소에 새로 생성되기 때문에 공유할 수 없다. (다른 객체이다)

 

 

 

 

 

 

 

StringBuilder

 

String에서 기존의 문자열에 문자열을 추가하는 방법으로 + 연산자를 사용 할 수 있다.

하지만 String은 불변성이 있으므로 + 연산을 하면 다음과 같은 일이 발생한다.

String str = "abc";
str += "def";

 

"abcdef"라는 새로운 값을 가진 메모리 영역이 생기고 그를 참조하게 바뀌게 된다.

따라서 + 연산이 발생할 때 마다 새로운 메모리를 할당하게 되고, 상당한 성능저하를 일으킨다.

 

여기서 대체할 수 있는 방안으로 StringBuilder가 있다.

 

Oracle Javadoc에는 StringBuilder를

mutable sequence로 정의하고 있다.

 

StringBuilder sb = new StringBuilder("abc");

sb.append("def");

String str = sb.toString();

sb객체는 생성될 때 "abc"라는 메모리에 할당하는 것이 아니라 버퍼에 가지고 있다.

그리고 append가 발생할 때 마다 버퍼의 끝에 문자열을 추가한다.

 

마지막으로 toString() 메소드를 통해 버퍼에 저장되어 있는 최종 값을 String으로서 메모리에 할당하는 것이다.

 

 

 

 

StringBuilder를 만드는 방법은

StringBuilder 변수이름 = new StringBuilder(문자열);

 

또한 StringBuilder로는 아래의 작업들을 할 수 있다.

sb.append(문자열); // 문자열의 끝에 새로운 문자열 추가
sb.insert(int index, String value); // index의 위치에 value 문자열 삽입
sb.remove(int index, int length); // index위치부터 length만큼 제거
sb.replace(String oldValue, String newValue); // oldValue문자열을 newValue문자열로 교체
sb.toString(); // String으로 바꿈

 

참고 자료 : www.dreamy.pe.kr/zbxe/CodeClip/158356

'Java' 카테고리의 다른 글

static 메소드 사용  (0) 2020.12.09
equals() Overriding  (0) 2020.12.09
Arrays.asList()  (0) 2020.12.06
Google Java Style Guide(번역)  (0) 2020.11.28
Java 접근지정자  (0) 2020.11.08