일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 오블완
- 스터디
- Android
- 자바
- 프로그래머스
- doitandroid
- Kotlin
- 정처기
- 혼공단
- 카카오코테
- groupby
- 정보처리기사
- join
- MySQL
- 기술면접
- 혼공챌린지
- 코틀린
- CS
- 코테
- SQL
- 인프런
- 알고리즘
- java
- 자료구조
- select
- 티스토리챌린지
- 혼공파
- 안드로이드스튜디오
- Til
- 안드로이드
- Today
- Total
Welcome! Everything is fine.
[Java] 동등성과 동일성, equals() 메서드 파헤치기 본문
자바에서 두 객체가 같다는걸 확인할 때, 두 가지로 표현할 수 있다는 것을 배웠다.
- 동일성(Identity) : == 연산자 이용, 두 객체의 참조가 동일한 객체를 가리키는지 확인
- 동등성(Equality) : equals() 메서드 이용, 두 객체가 논리적으로 동등한지 확인
강의를 보며 예제 코드로 실습을 하다가 이해가 가지 않는 부분이 있었다. User 객체를 생성해 동일성, 동등성 비교를 할 때, 모두 false가 출력된 것이다. 그리고 Object가 기본적으로 제공하는 equals()는 == 으로 동일성 비교를 제공한다는 것이었다. 그래서 '그럼 왜 euqlas()'라는 메서드를 만든거지? 라는 생각이 들었다.
User user1 = new User("id-100");
User user2 = new User("id-100");
System.out.println("identity= " + (user1 == user2));
System.out.println("identity= " + (user1.equals(user2)));
identity= false
equality= false
실제로 Object 클래스에 들어가 equals() 메서드를 보니 다음과 같이 되어있었다. 그럼 문자열을 비교할 때는 동등성과 동일성이 잘 비교되었는데, 왜 객체를 비교할 때는 비교가 안될까?
바로 동등성의 개념이 각각의 클래스마다 다르기 때문이다. User의 동등성은 아이디로 처리할 수도 있고, 주민등록번호, 혹은 전화번호로 처리할 수 있다. 그래서 단순히 User라는 객체만 가지고 비교를 한다면? 동등성 비교를 할 수 없다.
더 찾아보니, String 클래스의 equals() 메서드는 단순히 == 으로 비교하지 않는다. 내가 생각하는 이상적인 동등성 비교를 하려면 String 클래스에 오버라이딩된 equals() 메서드를 쓰면 되는 것이었다! 그렇다면 String 클래스로 들어가 equals() 메서드를 보자.
맨 처음 if문부터 살펴보면, this와 anObject가 동일한 참조인지 확인해서 같으면 true를 반환한다. 여기서 this는 equals() 메서드가 호출된 현재 String 객체를 의미한다.
if (this == anObject) {
return true;
}
그 다음으로는 anObject가 String 타입인지 확인한다. 다음 조건과 &&로 이어져 있기 때문에 String 타입이 아니면 바로 false가 반환된다.
return (anObject instanceof String aString)
앞의 조건을 통과했다면, COMPACT_STRINGS가 활성화된 경우, this와 aString의 coder 값이 같은지 확인한다. COMPACT_STRINGS가 무엇을 의미하는지 찾아보니 Java 9부터 도입된 문자열 메모리 최적화 기능의 일부로, 문자열을 메모리 효율적으로 관리하기 위해 사용된다고 한다. ASCII 문자열이면 1바이트(UTF-8) 인코딩, 그렇지 않으면 2바이트(UTF-16)로 인코딩되도록 최적화하는 기능이다.
&& (!COMPACT_STRINGS || this.coder == aString.coder)
그래서 COMPACT_STRINGS가 활성화 되어있다면,
- 두 문자열의 coder 값(각 문자열의 인코딩 방식)을 비교하여 같은 인코딩 방식인지 비교한다.
- coder 값이 같으면(=인코딩 방식이 같으면) 바이트 배열을 바로 비교할 수 있다.
- corder 값이 다르면(=인코딩 방식이 다르면) 비교를 진행하지 않고 불필요한 메모리 접근과 연산을 방지한다.
마지막으로, 두 문자열의 내용을 비교한다. 문자열 내용이 동일하면 true를, 그렇지 않으면 false를 반환한다.
StringLatin1.equals(value, aString.value);
StringLatin1 클래스에 들어가보니 다음과 같은 구조였다. 두 개의 byte 배열의 길이가 같은지 먼저 확인 후, 길이가 같으면 배열의 각 요소를 하나씩 비교하면서 모든 요소가 같을 경우에만 true를 반환한다.
이렇게 궁금한 점을 직접 코드를 보고 해석하며 해결해보았다! 그냥 대충 넘어가기보다 이렇게 하나씩 정리하니 더 이해도 잘 가고 기억에 오래 남을 것 같다.
'Java' 카테고리의 다른 글
[Java/Study] 김영한의 실전 자바 중급 1편 - 스터디 7회차 (0) | 2024.11.30 |
---|---|
[Java/Study] 김영한의 실전 자바 중급 1편 - 스터디 6회차 (2) | 2024.11.20 |
[Java/Study] 김영한의 실전 자바 기본 - 스터디 5회차 (2) | 2024.11.07 |
[Java/Study] 김영한의 실전 자바 기본 - 스터디 4회차 (0) | 2024.10.26 |
[Java/Study] 김영한의 실전 자바 기본 - 스터디 3회차 (4) | 2024.10.15 |