String을 생성하는 방법은 다음 두가지가 있다.
첫번째 방식은 str1과 str2가 가리키는 객체가 동일하다. 즉 둘 모두 동일한 주소의 "abc"라는 문자열 리터럴을 공유한다.
두번째 방식은 새로운 String 인스턴스를 생성한다. 즉 str3와 str4의 문자열 값 자체는 동일하지만, 두 객체가 가리키는 주소값은 다르다.
String 클래스는 불변이기 때문에, 첫번째 방식으로 두 개 이상의 String 클래스가 동일한 문자열 리터럴을 공유하더라도 큰 문제는 없다.
이에 따른 차이는 "==" 연산에서도 나타난다.
따라서 String 클래스에서 주소값의 비교가 아닌 실제 문자열 값을 비교하고 싶다면, == 보다는 "equals" 메소드를 사용해야 한다.
System.out.println(str1 == str2); //true
System.out.println(str1.equals(str2)); //true
System.out.println(str3 == str4); //false
System.out.println(str3.equals(str4)); //true
"compareTo" 메소드 역시 문자열의 비교에 사용할 수 있다. 해당 메소드는, 두 문자열이 같다면 0, 문자열이 사전순으로 더 앞선다면 -1, 뒤에 있다면 1을 반환한다.
System.out.println("aaa".compareTo("aaa")); //0
System.out.println("aaa".compareTo("bbb")); //-1
System.out.println("bbb".compareTo("aaa")); //1
앞서 설명했듯 StringBuffer는 내용 변경이 가능하다.
StringBuffer sb = new StringBuffer("abc"); //sb == "abc"
sb.append("123"); //sb == "abc123"
StringBuffer sb2 = sb.append("ZZ"); //sb == sb2 == "abc123ZZ"
equals가 오버라이딩 되어 있는 String과 달리, StringBuffer는 equals가 오버라이딩 되어 있지 않다. 즉 equals가 문자열의 내용으로 비교하지 않고 주소값으로 비교를 한다. 따라서 두 개의 StringBuffer의 문자열이 동일한지를 비교하기 위해서는 equals를 쓰기 전에 String으로 변환하는 작업이 요구된다.
StringBuffer sb = new StringBuffer("abc");
StringBuffer sb2 = new StringBuffer("abc");
System.out.println(sb == sb2); //주소 비교 -> false;
System.out.println(sb.equals(sb2)); //주소 비교 -> false;
String s = sb.toString();
String s2 = sb2.toString();
System.out.println(s.equals(s2)); //값 비교 -> true;
StringBuffer는 동기화되어 있기 때문에 멀티스레드 환경에서 안전하다. 그러나 동기화는 곧 성능 저하이기 때문에 싱글스레드 환경에서는 동기화가 없는 StringBuilder를 사용하면 더 나은 성능이 가능하다.