📌 코딩테스트를 풀던 중 StringBuilder 객체를 equals로 비교했는데 자꾸만 다른 값이 나왔다. 분명 자바의 정석에서 StringBuilder의 동등성 비교에 대해서 공부했는데 잊은 것 같아서 다시 정리 해보고자 했다.
동일성(Identity)
를 비교하는 메소드이다. 두 객체가 동일한 메모리 주소를 가리키는지를 확인한다.
/* Object 클래스의 equals 메서드 */
public boolean equals(Object obj) {
return (this == obj);
}
실행 중(Runtime)에 객체의 유일한 integer 값을 반환한다. Object 클래스에서는 heap에 저장된 객체의 메모리 주소를 반환하도록 되어있다. HashTable, HashMap, HashSet과 같은 자료구조를 사용할 때 데이터가 저장되는 위치를 결정하기 위해 사용된다.
public native int hashCode();
-> 동일한 객체는 동일한 메모리 주소를 갖는다는 것으로, 동일한 해시코드를 가져야한다.
-> 결국 equals 메소를 오버라이드 하면, hashCode 메소드도 함께 오버라이드 해야한다.
String의 경우 Object 클래스의 equals 메소드와 hashCode 메소드가 오버라이드 되어 있다.
그래서 String 클래스는 equals()
를 이용하여 동등성(Equality)
을 비교할 수 있다.
String str1 = new String("Good Morning~");
String str2 = new String("Good Morning~");
System.out.println(str1 == str2); // false
System.out.println(str1.equals(str2)); // true
String 클래스의 equals 메소드를 보면 첫 번째 if문에서 주소 값이 같은 객체라면 바로 true 값을 반환한다. 여기에서 동일한 객체는 동등한 객체임을 알 수 있다.
/* String 클래스의 equals 메소드 */
public boolean equals(Object anObject) {
if (this == anObject) { // 동일한 객체(주소 값이 같으면 true를 return
return true;
}
if (anObject instanceof String) { // 문자열의 문자를 하나씩 비교
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
/* String 클래스의 hashCode 메소드 */
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
hash = h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
}
return h;
}
StringBuilder는 String과 달리 equals 메소드와 hashCode 메소드를 오버라이드 하지 않았다. 따라서 StringBuilder의 동등성을 비교하기 위해서는 StringBuilder 객체를 toString()
을 이용해 String으로 변환한 후 equals 메소드를 사용하면 된다.
StringBuilder의 의도된 용도는 시간이 지남 에 따라 변경될 수 있는 문자 버퍼를 유지 관리하는 것으로, mutable한 객체이다.
hashCode()를 재정의 하지 않는 이유
해시 알고리즘을 사용하는 데이터 구조에서 Key로 사용되는 객체를 수정하면 저장된 값이 손실될 가능성이 있다. 따라서 StringBuilder는 변경 가능한 객체(mutable)에 대해 hashCode()를 재정의하는 것은 일반적으로 유용하지 않다.
equals()를 재정의 하지 않는 이유
두 객체가 equals 메서드로 같으면 해시 코드가 동일해야 한다. 즉, equals 메서드가 재정의된 경우 해당 hashCode 메서드도 재정의되어야 한다. 그러나 위의 이유처럼 고유한 해시코드 구현을 하지 않아서 equals 메서드도 재정의하지 않는다.
StringBuffer와 StringBuilder는 동기화
라는 한 가지 차이점을 제외하고 동일한 메서드를 가진다. 따라서 StringBuffer의 동등성 비교는 StringBuilder의 동등성 비교 방법과 동일하다.
StringBuffer는 동기화가 되지만, StringBuilder는 동기화를 지원하지 않는다.
즉, StringBuffer는 스레드로부터 안전하고, StringBuilder는 스레드로부터 안전하지 않다.
📍 참고한 사이트
https://getinterviewinfo.wordpress.com/2014/09/16/why-stringbuffer-and-stringbuilder-doesnt-override-equals-and-hashcode-method/
https://mangkyu.tistory.com/101
StringBuilder에 equals와 hashCode가 없는지 처음 인지했네요!
역시 자바 개발자들은 다 깊은 뜻이 있군요~~ 유익한 글 잘 읽었습니다.
StringBuilder에 equals와 hashCode가 없는지 처음 인지했네요!
역시 자바 개발자들은 다 깊은 뜻이 있군요~~ 유익한 글 잘 읽었습니다.
StringBuilder가 Object의 Equals()와 Hashcode()를 재정의 하지 않은 지는 몰랐네요.
항상 동등성 비교를 위해서는 toString()을 해야한다는 점을 잊지 않아야겠어요.
StrinbBuilder와 StringBuffer가 스레드안전 차이가 있는것은 아는데 그 차이가 정확히 무엇을 의미하는지 추가 포스팅이 있으면 좋을 것 같습니다. 좋은글 감사하니다
StringBuilder에 equals와 hashCode가 없는지 처음 인지했네요!
역시 자바 개발자들은 다 깊은 뜻이 있군요~~ 유익한 글 잘 읽었습니다.