이번 시간에는 Objects 클래스에 있는 deepequals 메서드가 어떻게 동작하는지 알아보도록 하겠습니다. 사실, 카톡에서 누군가 질문을 올려주셔서 뜯어보게 되었습니다.
먼저, Objects의 deepEquals를 보면, a와 b를 받습니다. 80번째 줄을 보면, a와 b가 같으면 true를 리턴합니다. 가리키는 객체가 같다면 true를 리턴합니다. 그리고, a가 null이거나 b가 null이면 false를 리턴합니다. 그렇지 않으면, Arrays.deepEquals0을 호출합니다. 그러면 이 함수를 보도록 하겠습니다.
뭔가 너무 길어 보입니다. 조건 구문만 대략 10개가 넘는 듯 싶어요. 이 중 8개는 기본 타임의 배열인 경우에 처리를 하는 루틴입니다. 예를 들어, instance of char[], instance of byte[] 조건이 각각, 4290번째 줄과 4282번째 줄에 있어요. 이 긴 코드를 3분할 해서 봅시다.
먼저, instanceof Object[]를 만족하는 경우를 생각해 봅시다. 이 경우는 어떤 경우일까요? 넘겨준 것이 다차원 배열이거나, 1차원 이상의 객체 배열인 경우입니다.
그림을 대략적으로 그려보시면 이해가 가능하실 듯 싶어요. int []는 어떤가요? Object를 기본 타입이 상속받지는 않아요. 그러니, 다른 조건절인, else if로 계속 타고 넘어갈 거에요. 어찌 되었던, e1과 e2의 객체 type을 Object []로 형변환 할 수 있다면, 4281번째 줄을 수행합니다. 이 메서드로 들어가 봅시다.
일단, a1과 a2를 객체의 배열로 생각해 봅시다. 만약에, a1과 a2가 같은 객체를 가리키고 있다면 true를 리턴해야 될 거에요. a1이나 a2가 null 값을 가지면 false를 리턴해야 할 거에요. 당연하게도, 배열의 길이가 다르면 false를 리턴해야 할 거에요. 이런 기본적인 처리를 한 다음에 무엇을 해야 할까요?
length만큼, a1[i]와 a2[i]를 deepEquals0 메서드로 비교를 해야 할 거에요. 이 상황을 그림으로 그려 봅시다.
여기서, a1[i]와 a2[i]를 비교합니다.
어떻게 비교하나요? a1[1]과 a2[1]를 deepEquals0로 비교했을 때, 다르다면, a1과 a2는 다르다는 결과가 나올 거에요. a1과 a2가 2차원 배열이였다면 어떨까요 a1[1]과 a2[1]은 1차원 배열이 아닌가요? 차원이 하나 줄어들었기 때문입니다.
이걸 그림으로 표현하면 위와 같습니다. 여기서, a1[1]은 위의 군청색 배열 객체를, a2[1]은 아래에 있는 군청색 배열 객체를 가리킵니다. 이 둘을 deepEquals0으로 비교해 보면 될 거에요. 함수 호출 trace를 대략적으로 그려보면 아래와 같습니다.
계속 이렇게 비교해 나가면 될까요? 차원이 계속 줄어서 0차원, -1차원, -2차원 이렇게 될 때 까지? 재귀 함수의 기본은 종료 조건에 있습니다. 언제 재귀를 끝낼 것인지에 대한 처리를 해야 한다는 것입니다.
이에 대한 기저 조건을 생각해 보면, 객체 타입이 넘어왔거나, 1차원 primitive type 배열이 넘어왔을 때 deepEquals0를 호출하지 않으면 됩니다. 먼저, 기본 타입의 1차원 배열에 대해서 생각해 봅시다.
8가지 경우가 있습니다. 이 때에는 어떻게 하면 되나요? primitive type이므로, 그냥 값 비교를 하면 될 거에요.
a와 b의 length만큼 탐색하면서, 하나라도 다른 게 있거나, 길이가 다른 게 있다면 false를 리턴해 버리면 될 거에요. 이것은 그리 어렵지 않습니다. 그런데, 객체이긴 한데, array가 아닌 경우가 있습니다. 예를 들자면, my_obj 객체 2개를 넘긴다던지. 그런 경우가 있을 수 있어요. 이 때에는 else 문이 수행이 됩니다.
equals 메서드가 수행됩니다. 깔끔한가요? '재정의한 type의 객체' 둘을 넘겼다고 가정해 봅시다. 내가 재정의한 type이, equals를 오버라이딩을 하지 않았다고 해 봅시다. 그러면, Object class에 있는 equals가 호출이 됩니다.
즉, a와 b가 같은 객체를 가리키는 지만 검사합니다. 같은 내용이 들어있는지 검사하지 않아요. 두 개의 내용이 같은지를 검사하기 위해서는, equals를 오버라이딩을 해야 한다는 것이 핵심 포인트입니다. 그런데 hashCode도 같이 해야 한다는 이야기는 책에서도 많이 보셨을 겁니다. 왜 그런지는 이 글을 보시면 좋을 듯 싶습니다. 그러면 문제 하나 드리겠습니다.
다음 코드를 생각해 봅시다.
MyObj형 2차원 배열 aa와 bb가 있습니다. 이 둘은 같은 내용을 저장하고 있습니다. 분명히 같은 내용을 담고 있으니까, 프로그램에 출력되는 값은 true일 거 같은데, false가 나옵니다. 왜 그럴까요? 그리고 deepEquals가 의도대로 동작하려면 어떻게 바꾸어야 할까요?
'레퍼런스 > 분석' 카테고리의 다른 글
java의 hashtable 대신에 왜 다른 것을 권장할까요? (2) | 2020.04.03 |
---|---|
c++ vector clear 함수 : size를 0으로 만들어 준다. (4) | 2020.03.21 |
c++ vector reserve vs resize : 미리 공간을 만들어 놓고 쓰면 안 될까요? (12) | 2020.02.05 |
java copyOf 메서드 : 배열을 복사한다. (5) | 2019.12.27 |
java hashset은 key의 해쉬 코드가 모두 같을 때 최악 복잡도가 어떻게 될까요? (6) | 2019.12.18 |
최근댓글