String은 우리가 코딩을 하면서 가장 많이 사용하는 객체중에 하나로 문자열을 담을 수 있는 타입이다.
그런데 String을 사용을 하면서 String변수는 바뀌지 않는다는 말은 들었는데 그게 무슨 소리인지 잘 이해가 되질 않았다.
왜냐하면
String str1 = "hello";
str1 = "hello world";
이렇게 선언하면 값이 바뀌기 때문이다.
그런데 사실은 이게 해당 메모리 값이 바뀌는게 아니라 생성자를 통해 새로운 String 객체를 만들어지게 된다.

위의 그림처럼 새로운 String객체가 생성되고, 기존에 생성되었던 "hello"라는 데이터를 가진 객체는 Garbage가 되어 메모리만 잡아먹고 있을 뿐이다.
그럼 아래의 코드를 보자
String str = "";
for (int i = 0; i < 100; i++){
str = str + "*";
}
System.out.println("str = " + str);
이 코드가 수행되는 과정은 아래 코드와 같다.
String str5 = "";
for (int i = 0; i < 100; i++){
str5 = new StringBuffer().append(str5).append("*").toString();
}
System.out.println("str5 = " + str5);
반복문을 100번 수행하는 동안 100개의 새로운 String객체와 StringBuffer가 생성될 것이고, 이는 메모리적으로나 수행시간적으로나 효율적이지 못한 방법이 된다. 그럼 차라리 StringBuffer를 사용하자.
StringBuffer / StringBuilder의 경우 가변성의 성격을 가지는데, append(), delete()메서드를 이용해 하나의 객체 내에서 문자열을 변경할 수 있다.

아래의 코드를 보자
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 100; i++) {
sb.append("*");
}
String str2 = sb.toString();
System.out.println("str2 = " + str2);
여기서는 가변하는 StringBuffer를 이용해 하나의 객체에 문자열을 추가하므로 가비지가 생기지도 않고 수행시간적으로도 String에 비해 효율적이다.
StringBuffer나 StringBuilder 모두 가변적인 특성을 가지고 있고, 사용 방법이나 메서드도 동일하다.
그러나 둘의 차이는 멀티쓰레드에서 안전하냐 아니냐 하는 차이이다.
하나는 멀티쓰레드에서 안전하고 하나는 멀티쓰레드에서 안전하지 않은 이유는 동기화(synchronized) 때문이다.
자바에서 동기화란 여러 쓰레드가 하나의 자원에 접근하려고 할 때, 데이터를 현재 사용하고 있는 쓰레드를 제외하고 나머지 쓰레드는 해당 데이터에 접근하지 못하도록 차단하는 역할을 한다.
하지만 동기화라는 추가적인 단계를 거치기 때문에 단일 쓰레드 환경에서는 StringBuilder가 속도 측면에서 우세하다.