String 클래스는 == 비교가 아니라 항상 equals()를 사용해서 비교를 해야한다.
package lang.string.equals;
public class StringEqualsMain1 {
public static void main(String[] args) {
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println("new String() == 비교: " + (str1 == str2));
System.out.println("new String() == 비교: " + (str1.equals(str2)));
String str3 = "hello";
String str4 = "hello";
System.out.println("리터럴 == 비교: " + (str3 == str4));
System.out.println("리터럴 == 비교: " + (str3.equals(str4)));
}
}
str1, str2는 new String()을 사용해서 인스턴스를 생성했다.
서로 다른 인스턴스이기에 ==은 실패한다.
둘은 내부에 같은 "hello"를 가지고 있기에 eqauls() 비교는 성공한다.
참고로 String 클래스는 내부 문자열을 비교할 수 있도록 오버라이딩이 되어 있다.
str3, str4처럼 리터럴을 사용하면 문자열 풀에서 "hello"라는 String 인스턴스를 찾는다.
문자열 풀 덕분에 같은 문자열을 사용하는 경우 메모리 사용을 줄이고, 문자를 만드는 시간도 줄일 수 있기 때문에 성능에 최적화 할 수도 있다.
프로그래밍에서 풀은 공용 자원을 모아두는 곳이다.
여러 곳에서 사용할 수 있는 객체를 필요할 때마다 생성하고 삭제하는 것은 비효율적이다.
대신에 문자열 풀에 필요한 String 인스턴스를 미리 만들어두고 여러곳에서 재사용할 수 있다면 성능과 메모리에서 최적화 할 수 있다.
참고로 문자열 풀은 힙 영역을 사용한다.
문자열 풀에서 문자를 찾을 때는 해시 알고리즘을 사용하기 때문에 매우 빠르게 찾을 수 있다.
package lang.string.equals;
public class StringEqualsMain2 {
public static void main(String[] args) {
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println("메서드 호출 비교1: " + isSame(str1, str2));
String str3 = "hello";
String str4 = "hello";
System.out.println("메서드 호출 비교2: " + isSame(str3, str4));
}
private static boolean isSame(String x, String y) {
// return x == y;
return x.equals(y);
}
}
isSame()의 경우 String 인스턴스가 new String()으로 만들어졌는지, 리터럴로 만들어졌는지 알 수가 없다.
그러니 문자열을 비교할 때는 equals()를 사용하도록 하자.