본문 바로가기

DEVELOPER/Java

[JAVA 파헤치기] Arrays, System.arraycopy 를 활용하여 배열 다루기

안녕하세요😎 백엔드 개발자 제임스입니다 :)

오늘은 프로그래밍의 기초 개념인 배열에 관해서 포스팅하려고 합니다. 포스팅하기 전에! 이번 포스팅은 배열의 기본적인 개념을 알고 있다는 가정하에 정리했음을 미리 알립니다.
따라서 이번 주제는 [배열 다루기] 입니다! :)

배열을 다루는 방법은 굉장히 많은데요. 그중에서 Arrays와 System.arraycopy에 대해서 설명하겠습니다. 여기서 배열을 다룬다는 의미는 배열을 복사하거나 추가, 삭제 등 다양한 기능을 의미합니다. 이제 자세하게 설명을 하도록 하겠습니다.



1. System.arraycopy()                


  • arrayclass는 이름 그대로 배열을 복사하는, System 클래스의 메서드입니다.
  • 해당 메서드는 반환을 하지 않는 void입니다.
void arraycopy(Object src, int srcPos, Object dst, int dstPos, int length)

* src : 원본 배열
* srcPos : 원본 배열에서 복사할 항목의 시작 인덱스
* dest : 새 배열
* destPos : 새 배열에서 붙여 넣을 시작 인덱스
* length : 복사할 개수

사용 예시

int[] srcArr = {1,2,3,4,5};

int[] destArr = {0, 0, 0, 0, 0};

System.arraycopy(srcArr, 0, destArr, 0, 5);

System.out.println(Arrays.toString(destArr));
위 코드에서 출력시 사용된 Arrays.toString 에 대해서는 아래에서 다룹니다.

위 코드를 예시로 설명하겠습니다. 먼저 결론부터 말하자면, 마지막 출력 구문에서 {1, 2, 3, 4, 5}로 srcArr 내용과 똑같이 출력됩니다. 여기서 알 수 있는 것은 srcArr의 내용이 destArr에 그대로 복사되었다는 것입니다.
즉, 'arraycopy 메소드를 통해서 srcArr의 인덱스 0번부터 길이 5만큼 해당하는 내용들을 destArr의 배열 0번부터 해당하는 위치 저장한다'라고 이해할 수 있습니다. 따라서 src의 인덱스 0번의 1부터 길이 5에 해당하는 정수 5가 destArr에 인덱스 0번부터 차례로 복사된 것이죠.
아래부터 다양한 방법으로 사용해보겠습니다.

#2 arraycopy안에 입력값 변경

int[] srcArr = {1,2,3,4,5};
int[] destArr = new int[6]; // {0, 0, 0, 0, 0, 0}

System.arraycopy(srcArr, 2 , destArr, 0, 3);

System.out.println(Arrays.toString(destArr));

이번에는 destArr을 크기가 6만큼 배열을 생성했습니다.
그리고 arraycopy의 인자로 (srcArr, 2, destArr, 0, 3)가 입력되었습니다. destArr은 어떠한 결과가 출력될까요?

  • srcArr의 인덱스 2번부터 길이 3만큼에 배열 -> {3, 4, 5}
  • destArr의 0번 부터 저장

따라서 결과는 [3, 4, 5, 0, 0, 0] 의 형태로 출력될 것입니다.

#3 destArr 크기 변경

int[] srcArr = {1,2,3,4,5};
int[] destArr = new int[3];

System.arraycopy(srcArr, 2 , destArr, 0,3);

System.out.println(Arrays.toString(destArr));

이번에는 destArr의 배열 크기를 3으로 줄여보았습니다. 결과는 destArr에 [3, 4, 5] 가 복사되어 출력됩니다.

#4 배열 중간에 복사하기

int[] srcArr = {1,2,3,4,5};
int[] destArr = new int[6];

System.arraycopy(srcArr, 0 , destArr, 2,4);

System.out.println(Arrays.toString(destArr));

이번에는 destArr의 복사받을 시작 위치를 인덱스 2로 했습니다. 그리고 srcArr의 인덱스 0번부터 길이 4만큼 복사를 합니다. 결과는 어떨까요?
destArr은 [0, 0, 1, 2, 3, 4] 가 됩니다.

#5 오류 발생

  • arraycopy의 입력된 값에서 length(복사할 길이)가 srcArr의 크기보다 크다면 ArrayIndexOutOfBoundsException이 발생합니다.
  • 복사 받을복사받을 배열의 크기가 복사받을 내용보다 작다면 동일한 에러가 발생합니다.

이처럼 크기와 관련해서 오류가 많이 발생하니 배열의 크기를 신경 쓰면서 사용하는 게 좋겠습니다.
추가로 위에서 알 수 있듯이 기존의 배열 내용이 있어도, 복사를 받으면 덮어쓰기가 됩니다.


 


2. Arrays 클래스              


  • 배열 복사, 항목 정렬, 항목 검색, 항목 비교를 위해 사용되는 클래스입니다.
  • Java.util 패키지에서 구현된 클래스입니다.
  • static 이므로 Arrays 클래스로 바로 사용 가능합니다.

Arrays는 배열을 쉽게 다룰 수 있도록 도와주는 도구와 같습니다. 이러한 도구를 잘 활용하기 위해서는 메서드들을 알고 있으면 좋습니다.


Arrays의 다양한 메서드

1) String toString(배열)

"[값1, 값2 ,,, ] " 와 같은 문자열 리턴
  • 배열 내의 값들을 일괄로 출력할 때 주로 사용합니다.
  • 단순히 System.out.println(arr); 사용할 시에는 주소값이 출력됩니다.
int[] arr = new int[]{1,5,2,4,8};

System.out.println(arr); // [I@3ac3fd8b
System.out.println(Arrays.toString(arr)); // [1, 5, 2, 4, 8]

 

2) void sort(배열)

배열 전체 항목을 오름차순으로 정렬
  • 타입이 void이기 때문에 새로운 변수, 주소값으로 받을 필요가 없습니다.
  • 아래와 같이 사용한 후 arr을 출력하면 정렬된 모습을 알 수 있습니다.
  • 오름차순 -> 1, 2, 3, 4,..
int[] arr = new int[]{1,5,2,4,8};

Arrays.sort(arr); // arr 배열 내부를 정렬시킴.

System.out.println(Arrays.toString(arr)); // [1, 2, 4, 5, 8]

 

3) copyOf(원본 배열, 복사할 길이)

원본 배열의 0번 인덱스에서 복사할 길이 만큼 복사한 배열 리턴
  • 복사할 길이는 원본 배열보다 커도 됩니다.
  • 이는 리턴되는 배열의 길이가 됩니다.
int[] arr = new int[]{1,5,2,4,8};

int[] copyArr = Arrays.copyOf(arr,5);

System.out.println(Arrays.toString(copyArr)); // [1, 5, 2, 4, 8]

현재 코드에서 arr 배열에서 길이 5만큼 복사한다고 지정해준 모습입니다. 보다시피 arr은 길이가 5이기 때문에 copyArr 또한 arr과 동일하게 값을 같습니다.
(*) 아래 코드가 중요한 포인트입니다.

int[] arr = new int[]{1,5,2,4,8};

int[] copyArr = Arrays.copyOf(arr,6);

System.out.println(Arrays.toString(copyArr)); // [1, 5, 2, 4, 8, 0]

해당 코드에서 copyOf의 인자를 보면, 복사할 길이가 6으로 arr의 길이보다 큰 것을 알 수 있습니다. 과연 결과는 어떻게 될까요?
copyOf는 복사할 길이가 원본 배열보다 크다고 해서 에러가 발생하지 않습니다. 대신 새로 생성된 배열에 빈 공간이 형성됩니다. 위 코드에 적힌 주석이 출력된 결과입니다. 이것을 다르게 생각해보면, copyOf 안에 적힌 length는 새로운 배열의 길이와 동일한 것을 알 수 있습니다.

4) copyOfRange(원본 배열, 시작 인덱스, 끝 인덱스)

원본 배열의 시작 인덱스에서 끝 인덱스 전까지 복사한 배열 리턴
  • copyOf() 메서는 원본 배열의 0번 인덱스부터 복사했다면, 해당 메서드는 범위를 지정하여 복사합니다.
int[] arr = new int[]{1,5,2,4,8};

int[] copyArr = Arrays.copyOfRange(arr,1,3);

System.out.println(Arrays.toString(copyArr)); // [5, 2]

보다시피 arr의 1번 인덱스부터 3번 인덱스 전(2번 인덱스)까지 복사한 것을 알 수 있습니다.
copyOfRange() 메서드도 끝 인덱스를 원본 배열보다 크게해도 에러가 발생하지 않습니다. 오히려 공간이 생기게 됩니다.
아래 코드가 그 예시입니다.

int[] arr = new int[]{1,5,2,4,8};

int[] copyArr = Arrays.copyOfRange(arr,2,6);

System.out.println(Arrays.toString(copyArr)); // [2, 4, 8, 0]

 

5) boolean equals(배열, 배열)

두 배결 비교 ( 단, 중첩 배열의 항목은 비교하지 않음, 배열의 1차 항목 값만 비교)

#1

int[] arr = new int[]{1,5,2,4,8};
int[] arr2 = new int[]{1,5,2,4,8};

boolean equal = Arrays.equals(arr, arr2);
System.out.println(equal); //true

#2

int[] arr = new int[]{1,5,2,4,8};
int[] arr2 = new int[]{1,5,2,4,9};

boolean equal = Arrays.equals(arr, arr2);
System.out.println(equal); //false

 

6) void fill(배열, 값) / void fill(배열, 시작 인덱스, 끝 인덱스, 값)

전체 배열 항목에 입력한 값으로 저장
or (배열, 시작 인덱스, 끝 인덱스, 값) : 시작 인덱스부터 끝 인덱스까지의 항목에만 입력한 값으로 저장

#1 fill(배열, 값)

int[] arr = new int[]{1,5,2,4,8};

Arrays.fill(arr,7);

System.out.println(Arrays.toString(arr)); // [7, 7, 7, 7, 7]

#2 fill(배열, 시작 인덱스, 끝 인덱스, 값)

int[] arr = new int[]{1,5,2,4,8};

Arrays.fill(arr,1,4,7);

System.out.println(Arrays.toString(arr)); // [1, 7, 7, 7, 8]

 

반응형