이 번에는 equals() 동작에 궁금점이 생겨 공부한 내용을 정리해보겠다.
equals()하면 == 과의 비교가 대표적으로 떠오른다. equals()는 값에 대한 비교를 하며 == 은 참조하는 주소를 비교한다. 그럼 equals()는 실제로 값 비교를 어떻게 하는 지에 대하여 깊이 탐구해 보겠다.
실제 equals()가 작동하는 코드를 보면서 하나하나 파헤져 보자. 코드는 내가 생각했던 거 보다 훨씬 짧고 간결했다.
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String aString = (String)anObject;
if (coder() == aString.coder()) {
return isLatin1() ? StringLatin1.equals(value, aString.value)
: StringUTF16.equals(value, aString.value);
}
}
return false;
}
제일 먼저 비교하는 것은 참조하는 주소값을 비교한다. 당연히 같은 곳을 바라보게 되면 값 또한 일치하는 것이 명백하기 때문에 가장 먼저 조건으로 확인을 한다.
두 번째로는 파라미터로 들어온 Object 타입의 변수를 String으로 형변환할 수 있는지 확인한다.
여기서 형변환 할 수 없다면 값 비교를 할 필요없이 바로 false가 반환된다.
세 번째로는 형변환된 매개변수와 인코딩 식별자를 비교하고 일치하지 않으면 false가 반환된다.
마지막으로는 동일한 방식으로 알맞은 디코딩을 진행하여 비교를 한다. 근데 여기서도 equals()라는 함수가 있다. 이에 대해서도 간단히 정리를 해보자!
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
for (int i = 0; i < value.length; i++) {
if (value[i] != other[i]) {
return false;
}
}
return true;
}
return false;
}
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
int len = value.length >> 1;
for (int i = 0; i < len; i++) {
if (getChar(value, i) != getChar(other, i)) {
return false;
}
}
return true;
}
return false;
}
static char getChar(byte[] val, int index) {
assert index >= 0 && index < length(val) : "Trusted caller missed bounds check";
index <<= 1;
return (char)(((val[index++] & 0xff) << HI_BYTE_SHIFT) |
((val[index] & 0xff) << LO_BYTE_SHIFT));
}
두 함수 내용은 서로의 길이를 확인하고 길이가 동일하다면 처음부터 끝까지 하나하나 비교하는 것으로 확인할 수 있다. 그런데 여기서 두 가지 차이점이 존재한다.
첫 번째는 StringUTF16의 경우 길이에 시프트 연산을 취하는 것과 두 번째로 StringLatin1의 경우에는 배열의 값으로 StringUTF16의 경우에는 getChar함수로 비교한다.
오늘은 String equals() 함수에 대해서 깊이있게 학습해보았다. 파면 팔수록 난이도가 올라가지는 느낌을 받았었다. 다음에 기회가 된다면 StringLatin1, StringUTF16에 대해서도 학습을 할 것이다.