
참조형 데이터로 힙 영역에서 문자열 데이터를 저장한다.
String은 불변 객체에 해당한다.
한 번 객체에 데이터를 할당하면 내부 데이터를 변경할 수 없는 객체
클래스를 final로 선언하고, 필드에 final을 사용하고, setter를 구현하지 않는다. 필드에 참조형 변수가 있는 경우 해당 변수도 불변 객체여야 한다. 참조에 의해 변경가능성이 있으면 방어적 복사를 이용하여야 한다.
// 1. 따옴표를 사용하여 문자열 생성
String str1 = "Hello World";
// 2. new 연산자 사용하여 문자열 생성
String str2 = new String("Hello World");
1번 방식으로 String을 생성하면 힙 영역에 존재하는 String Constant Pool 영역에 문자열을 저장한다.
String은 불변 객체이므로 재사용될 확률이 높으므로 String Constant Pool에서 따로 관리하여 재사용할 수 있도록 한다.
2번 방식으로 String을 생성하게 되면 새로운 객체를 따로 힙 영역에 계속 생성하게 된다.
String str1 = "Hello World";
String str2 = "Hello World";
String str = new String("Hello World").intern();
1번 방식으로 하는 경우 내부적으로 intern() 메서드를 호출한다.
intern() 메소드는 해당 문자열이 String Constant Pool에 존재하는지 확인하고 없으면 String Contant Pool에 넣는다.
String str = "";
str += "Hello";
str += " ";
str += "World";
기존에는 String + 연산을 사용하면 새로운 String 을 생성하게 됐는데 이제는 내부적으로 StringBuilder 나 StringBuffer를 사용하여 append 하여 최적화됐다.
가독성, 다운그레이드 등의 문제로 인하여 + 연산보다는 StringBuilder 나 StringBuffer를 사용하는 것이 더 좋다.
+를 할 때마다 매번 new StringBuilder()를 선언하여 새로 객체 생성하고 있어서 객체를 한 번 선언하고 append하는 것보다 성능이 떨어질 수 있다.
String str1 = "Hello ";
String str2 = str1.concat("World");
String.concat 메소드로 String 객체 자체에서 문자열 데이터 변경이 가능하다.
합친 문자열을 new String()으로 새로 생성한다.
StringBuilder sb = new StringBuilder();
sb.append("Hello ");
sb.append("World");
String str1 = sb.toString();
StringBuffer sbf = new StringBuffer();
sbf.append("Hello ");
sbf.append("World");
String str2 = sbf.toString();
String은 불변객체이지만 StringBuilder와 StringBuffer는 가변객체이므로 매 연산마다 새로운 객체를 생성하지 않는다.
StringBuilder는 단일 쓰레드에서 사용 시 더 성능이 좋고, StringBuffer는 내부에 synchronized가 선언돼서 멀티 스레드 환경에서 더 안전하다.
StringBuilder와 StringBuffer는 equals() 메서드를 오버라이딩하지 않으므로 String으로 변환한 후 문자열 동등성 비교를 할 수 있다.