*본 게시물은 개인 공부를 기록하기 위해 작성하였으며, 내용에 오류가 있을 수 있음을 밝힙니다.
제목에 대한 답을 얻기 위해서는 우선, 자바에서의 "동등성"과 "동일성"에 대해 이해해야 한다.
우리는 자바를 공부하면서 "동등성"과 "동일성", 그리고 "equals 메서드"와 "=="에 대해 들어본 적이 있을 것이다.
자바에서 동등하다는 것은 "값"이 같다는 것을 의미하고, 동일하다는 것은 "주소"가 같다 즉, 같은 객체를 가리킨다는 것을 의미한다.
또한, equals 메서드는 기본적으로는 주소비교지만, 오버라이딩 시 내용 비교가 가능하고, String, Integer, List, Set, Map 등은 기본적으로 내용 비교로 오버라이딩 되어 있다.
반면, 연산자 "=="은 기본형인 경우에만 "값"을 비교하고, 이외에는 항상 "주소"를 비교하여 결과값을 반환한다. 기본형은 변수에 값 자체가 저장되고, 객체이면 참조형 변수에 주소가 저장되기 때문이다.
이제 코드 예시를 통해 위 내용을 자세히 설명해볼텐데, 그전에 위의 내용을 잘 이해했는지 돌발 퀴즈! (답변은 제일 아래에)
Q) int a = 10, int b = 10일 때, a.equals(b)를 하면 어떻게 될까요?
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
<equals() 메서드>
우선, 본문에서 equals 메서드는 기본적으로 주소비교(동일 비교)라고 했었는데, 그와 관련된 예시 코드를 먼저 보여주자면


위 코드와 출력값을 보면, 직접 생성한 Val 클래스의 객체 v1, v2의 값을 동일하게 10으로 초기화하였음에도 불구하고 v1.equals(v2)의 값은 false가 나온다. 이는 equals 메서드가 기본적으로 "값"이 아닌 "객체가 가리키는 주소"를 의미한다는 것이다. 하지만, 코드의 11번째 줄에서 v2 = v1을 실행하고 나면 v1.equals(v2)의 값이 true로 바뀐다. 이 11번째 줄에서 v2가 가리키는 객체가 v1이 가리키는 객체와 같아졌기 때문이다.
하지만, equals 메서드가 항상 주소 비교(동일 비교)만 하는 것은 아니다!
본문에서 언급했듯이 오버라이딩 시에는 내용 비교(동등 비교)도 가능하고, String, Integer, List, Set, Map과 같이 기본적으로 내용 비교(동등 비교)를 하도록 오버라이딩 된 경우도 있다.
그와 관련된 예시 코드를 보여주자면


이 코드에서 s1과 s2는 별개의 객체이다. 즉, s1과 s2이 가리키고 있는 주소는 다르다.
그런데도 왜 s1.equals(s2)는 true일까?
-> String 클래스는 equals 메서드를 내용 비교로 오버라이딩 해놓았기 때문!
<연산자 "==">
이번에는 연산자 "=="에 대한 예시 코드를 보여주면서 상황에 따른 차이를 비교해 보겠다.
본문에서 "연산자 "=="은 기본형인 경우에만 "값"을 비교하고, 이외에는 항상 "주소"를 비교하여 결과값을 반환한다."라고 하였는데 이 설명에 대한 예시 코드를 보여주자면


위 코드를 보면 기본형 int형으로 초기화한 변수 a와 b는 "값"이 10으로 같으므로 "a==b"의 결과값이 true가 나왔다. 반면, Val클래스의 객체로 생성한 변수 v1과 v2는 "v1==v2"의 결과값이 false가 나왔다. 이 결과를 보면 본문에서 언급한 내용과 같다는 것을 알 수 있다.
정리하자면, equals() 메서드와 연산자 "=="은 모두 상황에 따라 "값"을 비교하는지, "주소"를 비교하는지가 달라지므로 어떤 상황에 어떤 식으로 비교하는지를 정확하게 알고 사용하는 것이 필수적이다.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
<돌발퀴즈 정답>
컴파일 오류가 나온다.
->기본형 변수는 객체의 참조형 변수와 달리 메서드를 사용할 수 없기 때문.
+추가)

이 경우 참조형 변수 s1과 s2가 가리키는 주소가 다를까?
-> 같다. (String Constant Pool 때문)
s1, s2는 new로 각각의 새로운 객체를 생성한 것이 아니다. 따라서 참조형 변수 s1이 선언될 때, 문자열 리터럴 "Hello"는 힙의 객체가 있는 공간이 아니라, 힙 내부의 String Pool이라는 특별한 메모리 공간에 저장된다. 이후, String s2 = "Hello"와 같이 같은 리터럴이 다시 등장하는 경우, "Hello"라는 리터럴을 String Pool에 새로 추가하는 것이 아니라 기존 풀에 있던 객체를 재사용한다. 즉, s2도 원래 있던 "Hello"를 가리키게 되는 것이다. 결국 s1과 s2는 같은 주소를 갖게 된다.
이는 int i1 = 10. int i2 = 10인 경우와는 다른 경우임에 주의해야한다. 기본형인 int는 주소가 아니라 값을 저장하기 때문에 i1, i2는 주소 자체가 존재하지 않는다.