배열은 객체이지만 Object 의 기본 구현을 그대로 쓴다. 그래서 내용이 같아도 다른 배열이다.
int[] a = {1, 2}, b = {1, 2};
a.equals(b); // false — 주소 비교
a.hashCode() == b.hashCode(); // 거의 항상 false — 식별 해시
Arrays.equals(a, b); // true
Arrays.hashCode(a) == Arrays.hashCode(b); // true
그래서 키로 쓰면 못 찾는다
Map<int[], String> map = new HashMap<>();
map.put(new int[]{1, 2}, "값");
map.get(new int[]{1, 2}); // null — 새 배열은 다른 해시
넣을 때 쓴 바로 그 배열 객체로만 찾을 수 있다. 사실상 쓸 수 없는 키다.
왜 재정의하지 않았나
배열은 언어가 직접 만드는 특수한 객체이고, 내용 비교를 기본으로 삼으면
모든 배열 비교가 O(n) 이 된다. 자바는 기본을 싸게 두고, 필요한 쪽이
Arrays 유틸을 부르도록 했다.
다차원은 한 겹 더
Arrays.equals(x, y) // 1차원까지만 내용 비교
Arrays.deepEquals(x, y) // 중첩 배열까지 재귀 비교
Arrays.deepHashCode(x) // 마찬가지
int[][] 를 Arrays.equals 로 비교하면 안쪽 배열들을 주소로 비교해 false 가 나온다.
대안
키가 필요하면 List<Integer> 나 record 로 감싼다. 둘 다 내용 기반 계약을 갖는다.