Java

Object 클래스의 equals메서드 (feat. Casting Reference Types)

Yeji Heo 2024. 1. 20. 14:52

 

지난 글에서 모든 Class들의 최상위 클래스가 Object라는 것을 살펴보았고,

Object의 toString()메서드를 각 클래스들이 어떻게 오버라이딩해서 쓰고 있는지 확인했다.

 

이번에는Object의 메서드 중  equals()메서드를 살펴보려고 한다.

Object obj를 파라미터로 받는 메서드인 만큼, Reference타입의 Casting에 대해서도 언급하려고 한다!


 

1. (인스턴스1 == 인스턴스2) 의 결과는??

 

아래와 같이 Example 클래스를 인스턴스화 하여 1, "안녕"으로 상태 값을 설정했다고 하자.

// Example클래스의 인스턴스 e1, e2생성
Example e1 = new Example(1, "안녕");
Example e2 = new Example(1, "안녕");

이처럼 두 인스턴스의 상태 값을 같게 설정했다.

그럼 e1==e2 는 true일까?

==> 정답은 false !!

 

e1, e2는 인스턴스의 식별성을 담당한다. 

식별성에 대해 ==는 존재할 수 없는 것이다. 모~두 서로 다르다. 

 

그림을 그려보면 쉽게 알 수 있다.

e1는 참조값x를 통해, e2는 y를 통해 그림과 같이 서로 다른 것을 참조하고 있다.

그러므로 e1과 e2는 다르다고 보는 게 당연하다.

 


 

2. Object의 equals()

우리는 직관적으로 '상태값'이 같으면 '같다'를 return하는 결과를 원한다.

그러나 ==를 통해서는 상태값을 비교할 수 없었다. 

 

그렇다면 Object의 equals() 이걸 써보면 어떨까?

 

 

 

이 메서드는 Object타입의 obj를 넘겨받아서, this object와 같으면 true를 반환한다고 한다.

e1.equals(e2)

이런 식으로 Example 인스턴스 참조 값을 넘기며 사용할 수 있다.

 

그런데 equals()의 파라미터는 Object타입이었는데 

어떻게 인자로 Example타입을 넘기는가?

 

Example은 Object를 상속하기 때문이다. Java에서 모든 클래스의 최상위 클래스는 Object였다.

Object obj = new Example()과 같은 표현이 가능한 것이다.

Object가 Example보다 '개념적으로' 크기 때문에 Upcasting이 일어난다.

 


 

본론으로 돌아와서, equals()로 상태값을 비교할 수 있는지를 마저 보겠다.

도큐먼트도 읽어봤으니, 백문이 불여일견 코드를 열어보자.

java.lang.Object의 소스코드이다.

 

 

앞서 파악한대로 Object obj를 파라미터로 하며, 이를 this와 비교하게 된다. 

결국 또 참조값끼리 비교 연산을 하므로 ==과 같은 결과(false)가 도출될 것이다.

 


 

3. 그럼 상태값 비교는ㅠㅠ? (오버라이딩!)

Java의 API중 레퍼런스 타입 변수의 '상태값'을 비교하는 메서드는 없다고한다. 

그래서 클래스들은 상태값을 비교하도록(혹은 본인이 원하는 결과대로) 오버라이딩 해서 equals()를 사용한다.

 

앞서 예를 든 e1과 e2인스턴스에서

각각이 가진 num의 상태 값을 비교하고 싶다면,

아래와 같이 equals를 오버라이딩 할 수 있다.

	public boolean equals(Object obj){
		return this.num == ( (Example)obj ).num;
	}

this와 obj 참조값을 비교하는 것이 아니라, num에 접근해 그들을 비교하도록 오버라이딩 한 것이다.

 

 

==> 단, 눈 여겨 볼 부분은 (Example)로의 Downcasting이다.

e1.equals(e2)

 

우리는 Example 타입의 인스턴스 e2를

Object타입의 obj로 넘겨받았다. (Upcasting 되었다.)

앞서 언급한 대로 Example은 Object를 상속받기 때문에 자동 형 변환이 가능한 것이다. 

 

Upcasting을 했기 때문에 참조 가능한 범위가 줄어들었다. ( 하위(상위+자신) -> 상위)

그런데 이제는 또 Example(하위 클래스)이 갖고 있는 필드인 num에 접근해야 한다.

 

Object로 Upcasting된 obj는 더 이상 Example의 필드와 메서드에 접근할 수 없는데...우짜지??

이럴 때 다시 Downcasting를 해주어 하위 클래스를 복구하고, num에 접근한다! 

 

+ Java에서 레퍼런스 타입 변수의 Downcasting은

존재하지 않는 영역을 참조 시도 할 가능성이 있어 허용이 안 되지만,

위 예시처럼 Upcating을 한 이후에! Downcasting을 하는 것만 예외적으로 가능하다고 한다.


 

+ 4. String클래스가 오버라이딩 한 equals()

수 많은 클래스들이 equals()를 오버라이딩 하여 사용하고 있다.

아래는 java.lang.String 클래스의 equals()이다.

 

 

이 역시, 참조 값 자체가 같으면 더 볼 것도 없이 true를 return하고,

그렇지 않으면 String인지 보고~(파라미터가 Object였으니까! )

길이가 같은지도 보고~ 

길이가 같다면 한 글자씩 순서대로 상태값을 비교하도록 오버라이딩 되어 있었다!! 

 


+ 오늘의 여담

 

요즘 Java API 도큐먼트 읽는 게 아주 재밌다..!!!

필드나 메서드마다 특성에 맞게 적절한 키워드, 메서드 시그니처를 정의한 것을 보고

선배 개발자님들 짱이다...! 혹은 이렇게도 모델링을 하는구나..!!! 라고 생각하는 요즘이다.

 

아직은 API나 개발 스킬을 많이 알지 못하지만,

이렇게나마 꾸준히 귀동냥해서 내 코드에 적용하도록 해야겠다!!