목차
개요
자바에서 문자열을 비교하려고 하는 할 때, 내가 생각했던 것과 다른 결과가 나온 경험이 있습니다. 그 이유는 동등성과 동일성이라는 것의 차이에 있습니다.
동등성 (Equality)
두 객체의 내용(값)이 같은지를 비교합니다. `equals()` 메서드를 사용합니다.
equals()
Object 클래스의 메서드이며, 문자열의 경우 String 클래스에서 오버라이드되어 있습니다.
내부적으로 문자열의 각 문자 값을 순서대로 비교하여 내용이 같은지를 확인합니다.
equals() 메서드 내부 동작
Object를 상속받은 String 클래스의 equals를 확인해보면 다음과 같이 equals 메서드가 오버라이드되어 있습니다.
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
return (anObject instanceof String aString)
&& (!COMPACT_STRINGS || this.coder == aString.coder)
&& StringLatin1.equals(value, aString.value);
}
- `if (this == anObject)` : 현재 문자열과 비교하는 문자열이 같은 객체인 경우 true를 반환합니다. 동등성 안에서 동일성 비교도 체크하는 것입니다.
- `anObject instanceof String aString` : 비교 대상이 문자열인지 확인합니다. (매개변수로 Object를 받았기 때문이다.)
- `!COMPACT_STRINGS || this.coder == aString.coder` : 문자열 내부 인코딩(coding)이 같은지 확인합니다.
- `StringLatin1.equals(value, aString.value)` : 실제 문자 배열도 같은지 확인합니다.
`StringLatin1.equasl()`가 정의된 것을 확인해보면, 다음과 같습니다.
@IntrinsicCandidate
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;
}
- 두 문자 배열을 확인하여, 하나라도 틀리면 false를 반환하게 되어있습니다.
동일성
두 객체의 참조(주소)값이 같은지를 비교합니다. `==` 연산자를 사용합니다. 즉, 두 변수가 동일한 객체를 가르키고 있는지를 확인합니다.
문자열 리터럴 처리 방식
자바 컴파일러는 문자열 리터럴을 `String Constant Pool`에 저장하고, 동일한 리터럴이 나타나면 기존 객체를 재사용합니다. 다음 코드를 통해 그 과정을 살펴봅시다.
public class StringCompare {
public static void main(String[] args) {
String a = "hello"; // 문자열 리터럴
String b = "hello"; // 문자열 리터럴
System.out.println(a == b); // true - 동일성 비교
}
}
두 변수 모두 동일한 문자열 리터럴 `"hello"`를 사용하고 있습니다. 근데 왜 `a == b`가 `true`일까요? 그 이유는 다음과 같습니다.
자바 컴파일러(javac)는 `"hello"` 리터럴을 미리 분석하고 문자열 상수 풀(String Constant Pool)에 넣습니다.
String a = "hello"; // 상수 풀에서 "hello" 객체를 참조
String b = "hello"; // 동일한 "hello" 객체를 참조
즉, `"hello"`라는 동일한 String 객체의 참조를 `a`와 `b` 모두 갖게 됩니다.
동등성과 동일성 차이와 예제 코드
public class StringCompare {
public static void main(String[] args) {
String a = "hello"; // 문자열 리터럴
String b = "hello"; // 문자열 리터럴
String c = new String("hello");
System.out.println(a == b); // true - 동일성 비교
System.out.println(a == c); // false - 동일성 비교
System.out.println(a.equals(c)); // true - 동등성 비교
}
}
- `a`와 `b`는 문자열 상수 풀(String Constant Pool)에 하나의 객체를 같이 참조하고 있다.
- `c`는 새로운 객체를 생성한 것이라 `a와 b`와는 다른 참조값을 갖는다.
'JAVA' 카테고리의 다른 글
[Java] Lombok 라이브러리 (0) | 2025.05.10 |
---|---|
[Java] Optional (0) | 2025.05.04 |
[Java] Enum (0) | 2025.05.04 |
[Java] Lv_4 도서관 프로젝트 (0) | 2025.05.02 |
[Java] Lv_3 도서관 프로젝트 (0) | 2025.05.02 |