[Java] String Immutable

JAVA / / 2021. 8. 25. 21:33

String 과 StringBuffer, StringBuilder 의 가장 큰 차이점은 Immutable 속성이다. 빌더와 버퍼는 변경이 가능한 객체이지만 스트링은 불변(immutable)하다.

이 속성 때문에 String에 + 연산자를 사용하게 되면 시간복잡도가 기하급수적으로 늘게 된다. 

밑에 제출이 String에 + 연산을 사용해서 출력한것이고 위에 제출이 StringBuilder만 이용해서 해결한 코드이다.

보이는 것처럼 실행시간이 엄청나게 차이가 난다..

 

String은 결국 참조 타입임에도 불구하고 직접적으로 new 연산자를 통해 객체를 생성에 메모리에 올려 사용하기보단 String s = "Hello"   와 같이 문자열 리터럴형태로 사용이 허용된다.

하지만 이 String 객체는 최초에 한번 생성되면 절대로 그 값이 변하지 않는다..( Immutable)

따라서 또 String s = "real Hello" 라는 코드를 입력해도 객체가 변경된것이 아닌 내부적으로 새로운 String 객체가 생성되어 그 참조가 s에 담기게 된것이다. 결국 최소 생성된 문자열 리터럴 "Hello" 와 "real Hello"  두 개의 객체가 heap에 생성되어 있는 상태다.

 

이렇게만 보면 굉장히 불편해보이는데 검색을 해보니 이러한 성질은 JAVA 창시자인 제임스 고슬링의 의도대로 설계되었다고 한다.  String 타입에 Immutable 속성을 만든이유는 크게 String 객체의 캐싱 기능을 통해 힙을 절약하는 것이라고 볼 수 있다. 문자열 객체는 대체로 많이 사용되는 문자열이 형태가 존재한다. 예를 들어 프로그램에서 "Hello" 라는 문자열 객체를 사용자 요청때마다 생성하게 되면 힙에 사용자 요청 수만큼 "Hello"라는 값을 가진 문자열 객체가 쌓일 것이다. 그래서 우리는 한번 생성된 리터럴은 계속해서 생성하지 않고 사용할 수 있다.

for(int i = 0; i < 500; i++) {
    String str = "Hello World";
    System.out.println(str);
}

str은  "Hello World"라는 리터럴 객체를 계속 가져온다. 

 

결론적으로 String 의 더하기 연산은 immutable한 속성떄문에 객체를 수정하는 것이아닌 더하는 String 리터럴 객체마다 생성되고 이들을 모두 더한 최종 리터럴 String 객체가 생성되는 것이다.. 따라서 heap에 많은 문자열 객체가 생성되니 반복문에 이러한 String 의 더하기 연산이 들어가면 비효율적인 시간,공간복잡도 발생로 이어질 수 있다.

 

StringBuilder 와 StringBuffer의 차이는

StringBuilder는 동기화를 지원하지 않아 성능이 뛰어난 대신,

StringBuffer는 동기화를 지원해 멀티쓰레드 환경에서 안전하다는 장점이있다.

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기