Arrays 클래스
Arrays 클래스에는 java의 배열을 다루기 위한 다양한 메서드가 제공된다.
특징
- 항목정렬, 항목검색, 항복비교와 같은 메서드들을 제공
- java.util 패키지에 포함되어 있는 클래스로 import문을 추가하여야 사용이 메서드 사용이 가능하다.
- Arrays 클래스의 모든 메서드는 static 으로 구성되어 있기 때문에 구현체없이 바로 사용이 가능하다.
메서드 | 설명 |
asList(값들) | 전달받은 배열을 고정크기의 List로 반환한다. |
binarySearch(배열, 찾는 값) binarySearch(배열, 시작인덱스, 끝인덱스, 찾는 값) |
전달받은 배열에서 key에 해당하는 값을 이진탐색 알고리즘을 통해 탐색 후 해당 인덱스를 반환한다. 배열이 정렬되어 있어야 이진탐색알고리즘이 제대로 동작한다 |
copyOf(배열, 길이) | 전달받은 배열에서 길이만큼 새로운 배열로 복사하여 반환 |
copyOfRange(배열, 시작인덱스, 끝인덱스) | 전달받은 배열에의 시작인덱스부터 끝인덱스의 전까지를 복사하여 새로운 배열로 반환한다. |
deepEquals(배열, 배열) | 중첩된 배열까지 포함하여 두 배열이 같은지 비교한다 - equals와의 차이는 예시코드 참고 |
equals(배열, 배열) | 두 배열이 같은지 비교한다 (중첩배열은 확인하지 않음) - deepEquals와의 차이는 예시코드 참고 |
fill(배열, 값) fill(배열, 시작인덱스, 끝인덱스, 값) |
배열의 전체를 값으로 채운다. 시작인덱스와 끝인덱스가 있으면 해당 구간만 값으로 채운다. |
hashCode(배열) | 배열의 hashcode 값을 반환한다. |
sort(기본타입배열) sort(객체배열) sort(객체배열, Comparator) |
배열을 정렬한다. 기본적으로 오름차순으로 정렬하며, Comparator가 있을 경우 Comparator에 맞춰서 배열이 정렬된다. |
toString(배열) | 배열을 "[ 값1, 값2, 값3, ...]" 과 같은 문자열로 반환한다. |
asList(값들)
asList는 매개변수의 값들을 Collection 의 List로 반환한다.
List<Integer> list = Arrays.asList(1,2,3,4);
System.out.println(list.get(0)); // 1
System.out.println(list.get(1)); // 2
binarySearch(배열, 찾을 값)
binarySearcy를 사용하기 위해서는 배열이 정렬되어 있어야 한다 (이진탐색 알고리즘을 사용하기 때문)
int[] a = {3, 4, 5, 6, 7, 8, 10, 15, 27};
int idx1 = Arrays.binarySearch(a, 5);
int idx2 = Arrays.binarySearch(a, 10);
int idx3 = Arrays.binarySearch(a, 11);
System.out.println(idx1); // 2
System.out.println(idx2); // 6
System.out.println(idx3); // -8
찾는 key값이 배열에 없는 경우 음수를 리턴한다.
위의 코드에서 idx3의 값이 -8이 출력되었는데 이 값에서 2의 보수를 취하면 (-1을 곱한 후 1을 빼는 과정) 7이 되고, 이 값이 해당 배열에서 검색한 값이 위치할 인덱스가 된다.
만약 11이라는 값이 들어간다면 7인덱스에 추가해야 한다는 뜻이 되는 것이다. (뒤의 요소들은 한칸씩 밀린다고 생각할때)
copyOf(배열, 길이)
배열에서 길이만큼 복사하여 새로운 배열로 반환한다.
int[] a = {1,2,3,4,5};
int[] b = Arrays.copyOf(a, a.length);
System.out.println(Arrays.toString(a)); // [1, 2, 3, 4, 5]
System.out.println(Arrays.toString(b)); // [1, 2, 3, 4, 5]
System.out.println(a); // [I@7c30a502
System.out.println(b); // [I@49e4cb85
Arrays.toString 메서드로 출력한 결과를 보면 a배열이 b배여로 잘 복사된 것을 볼 수 있다.
또, 두 배열의 hashcode가 다른 것을 볼 수 있는데, 이는 객체가 다르다는 뜻으로 새로운 배열이 반환되었음을 알 수 있다.
copyOfRange(배열, 시작인덱스, 끝인덱스)
배열에서 시작인덱스부터 끝인덱스까지를 복사하여 새로운 배열로 반환한다.
int[] a = {1,2,3,4,5,6,7};
int[] b = Arrays.copyOfRange(a, 2, 5);
System.out.println(Arrays.toString(a)); // [1, 2, 3, 4, 5, 6, 7]
System.out.println(Arrays.toString(b)); // [3, 4, 5]
System.out.println(a); // [I@7c30a502
System.out.println(b); // [I@49e4cb85
배열 b에 a의 [2, 5) 인덱스까지 복사되어 반환된 것을 볼 수 있다.
copyOf와 마찬가지로 두 배열의 hashcode가 다르기 때문에 새로운 배열이 반환된 것을 알 수 있다.
deepEquals(배열, 배열) 와 equals(배열, 배열)
equals는 두 배열의 요소가 같은 값인지 1차 항목의 값만 비교한다.
deepEquals는 두 배열의 중첩된 항목까지 비교한다.
int[] a = {1, 2, 3, 4, 5, 6, 7};
int[] b = {1, 2, 3, 4, 5, 6, 7};
System.out.println(Arrays.equals(a, b)); // true
int[][] c = {{1, 2}, {3, 4}};
int[][] d = {{1, 2}, {3, 4}};
System.out.println(Arrays.equals(c, d)); // false
System.out.println(Arrays.deepEquals(c, d)); // true
equals 메서드로 a와 b를 비교하면 당연히 true가 반환될 것이다.
반면, c 와 d를 equals를 통해 비교하면 두 배열의 값이 같음에도 false가 반환된다.
이렇게 배열 안에 중첩 배열이 있다면 deepEquals를 통해 비교하여야 한다.
deepEquals 메서드가 어떻게 동작하는지를 보기 위해 구현된 deepEquals의 코드를 보자.
아래 코드는 Arrays 클래스에 구현된 deepEquals 메서드를 가져왔다.
// Arrays 클래스에 구현된 deepEquals 메서드
public static boolean deepEquals(Object[] a1, Object[] a2) {
if (a1 == a2)
return true;
if (a1 == null || a2==null)
return false;
int length = a1.length;
if (a2.length != length)
return false;
// 반복문으로 모든 요소를 순회한다
for (int i = 0; i < length; i++) {
Object e1 = a1[i];
Object e2 = a2[i];
// 두 배열의 해시코드가 같은지 비교 (해시코드가 같으면 같은 배열)
if (e1 == e2)
continue;
if (e1 == null)
return false;
// 중첩 배열을 비교하기 위해 deepEquals0 메서드를 호출한다.
// deepEquals0 메서드에서는 primitive type인지 검사하고,
// 1. primitive type 이 아니라면 deepEquals를 재귀적으로 호출
// 2. primitive type 이라면 equals 메서드를 호출.
boolean eq = deepEquals0(e1, e2);
if (!eq)
return false;
}
return true;
}
static boolean deepEquals0(Object e1, Object e2) {
assert e1 != null;
boolean eq;
// Object[] 배열이므로 다시 재귀적으로 deepEquals를 호출한다.
if (e1 instanceof Object[] && e2 instanceof Object[])
eq = deepEquals ((Object[]) e1, (Object[]) e2);
// primitive type의 배열이므로 equals로 비교한 후 결과 리턴
else if (e1 instanceof byte[] && e2 instanceof byte[])
eq = equals((byte[]) e1, (byte[]) e2);
else if (e1 instanceof short[] && e2 instanceof short[])
eq = equals((short[]) e1, (short[]) e2);
else if (e1 instanceof int[] && e2 instanceof int[])
eq = equals((int[]) e1, (int[]) e2);
else if (e1 instanceof long[] && e2 instanceof long[])
eq = equals((long[]) e1, (long[]) e2);
else if (e1 instanceof char[] && e2 instanceof char[])
eq = equals((char[]) e1, (char[]) e2);
else if (e1 instanceof float[] && e2 instanceof float[])
eq = equals((float[]) e1, (float[]) e2);
else if (e1 instanceof double[] && e2 instanceof double[])
eq = equals((double[]) e1, (double[]) e2);
else if (e1 instanceof boolean[] && e2 instanceof boolean[])
eq = equals((boolean[]) e1, (boolean[]) e2);
else
eq = e1.equals(e2);
return eq;
}
즉 deepEquals는 각 요소가 또다른 배열인지 검사하여
요소가 배열이라면 재귀적으로 자신을 호출하여 값이 같은지를 비교하는 것을 알 수 있다.
fill(배열, 채울값), fill(배열, 시작인덱스, 끝인덱스, 채울값)
배열을 내가 원하는 값으로 채워주는 메서드.
int[] a = new int[10];
Arrays.fill(a, 20);
System.out.println(Arrays.toString(a)); // [20, 20, 20, 20, 20, 20, 20, 20, 20, 20]
내가 원하는 인덱스 범위만 원하는 값으로 채워줄 수도 있다.
int[] a = new int[10];
Arrays.fill(a, 5, 9, 20);
System.out.println(Arrays.toString(a)); // [0, 0, 0, 0, 0, 20, 20, 20, 20, 0]
hashCode(배열)
배열의 hashcode 값을 반환한다.
int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
System.out.println(Arrays.hashCode(a)); // 30817
System.out.println(Arrays.hashCode(b)); // 30817
해시코드 값은 두 객체가 같은 객체인지 확인하는 코드
해시코드가 다르면 두 객체는 다른 것.
해시코드가 같다면 두 객체는 같을 수도 있고, 다를 수도 있다.
sort(기본타입배열)
sort(객체배열), sort(객체배열, Comparator)
sort(기본타입 배열)
int[] a = {5, 12, 8, 19, 20, 55, 882, 11, 1};
Arrays.sort(a);
System.out.println(Arrays.toString(a)); // [1, 5, 8, 11, 12, 19, 20, 55, 882]
// int 타입을 Integer타입으로 변환해야 한다.
Integer[] wrapA = Arrays.stream(a).boxed().toArray(Integer[]::new);
Arrays.sort(wrapA, Comparator.reverseOrder());
System.out.println(Arrays.toString(wrapA)); // [882, 55, 20, 19, 12, 11, 8, 5, 1]
- 기본타입 배열은 기본적으로 오름차순으로 정렬된다.
- 기본타입이란 byte[], char[], double[], long[], int[], float[], short[] 등이 해당된다.
- 그렇다면 primitive type에서 내림차순으로 정렬하고 싶다면?
기본타입 배열을 래퍼클래스로 만들어 Comparator를 두 번째 인자에 넣어줘야 한다.
sort(객체배열), sort(객체배열, Comparator)
String[] arr = {"banana", "card", "apple", "kakao"};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
Arrays.sort(arr, Comparator.reverseOrder()); // [apple, banana, card, kakao]
System.out.println(Arrays.toString(arr)); // [kakao, card, banana, apple]
- 문자열 객체도 오름차순으로 정렬되었다.
- 객체배열에서는 Comparator를 통해 내림차순으로도 정렬이 가능하다.
toString(배열)
배열의 각 요소들을 "[값1, 값2, 값3, ... ]" 형태의 문자열로 변환한다.