배열은 같은 자료형의 데이터를 연속된 메모리 공간에 젖아하는 구조이다.
각 데이터는 배열의 시작 주소를 기준으로 일정한 간격으로 배치되면 인덱스를 통해 빠르게 접근할 수 있다.
배열의 핵심적인 특징은 다음과 같다.
Java에서 배열은 기본 자료형 변수(int, float 등)와 달리 new연산자를 사용하고 Stack에는 배열의 시작 주소만을 담으며, 데이터는 Heap 영역에 저장된다.
메서드가 종료되면 Stack에 있는 주소값은 삭제되지만, Heap 영역의 배열 데이터는 바로 삭제 되지 않는다.
Java는 이런 경우 Garbage Collector(GC)가 자동으로 처리하며, GC는 배열을 참조하는 변수가 없어지면 메모리를 자동으로 회수하여 메모리 누수를 방지한다.

배열의 첫 번째 인덱스는 0이고 마지막은 배열의 길이(length) - 1이다.
int[] arr = { 1, 2, 3, 4, 5 }
// 0, 1, 2, 3, 4
이 왜 0부터 시작하는 지는 배열의 요소에 접근하는 공식을 통해 알 수 있다.
요소의 주소 = (시작 주소) + (자료형의 크기) * 인덱스
배열은 위의 공식을 이용해 요소에 접근하는데 0이 아닌 인덱스부터 시작한다면 매 접근마다 0과 시작 주소의 차이 만큼을 더하거나 빼야하기 때문이다.
Java에서 다차원 배열은 실제로는 배열의 배열(Nested Array) 형태로 구현된다.
예를 들어 2차원 배열은 다음과 같이 선언된다.
int[][] arr = new int[3][4];
이 때 메모리 구조는 아래와 같다.

Java의 배열은 배열의 배열로 구현되는 특징으로 인해 배열은 각각 다른 길이로 배열을 생성할 수 있다.
int[][] jagged = new int[3][];
jagged[0] = new int[2];
jagged[1] = new int[3];
jagged[2] = new int[1];
이처럼 행마다 다른 크기의 배열을 가지는 형태를 가변 배열이라 부르며, 메모리를 효율적으로 사용할 때 유리하다.
정렬은 데이터를 일정한 규칙(크기순 등)으로 배열하는 작업이다.
정렬된 배열은 검색이나 데이터 처리를 더 빠르게 할 수 있다.
자바에서 제공하는 기본 정렬은 내부적으로 퀵 정렬과 병합 정렬을 혼합한 방식을 사용한다고 한다.
얕은 복사는 배열의 참조 값(시작 주소)를 복사하여 동일한 배열을 참조하게 하는 방식이다.
int[] a = { 1, 2, 3 };
int[] b = a;
b[0] = 100; // a[0]도 함께 변경됨

깊은 복사는 배열의 데이터 값을 직접 복사하여 완전히 독립된 배열을 만드는 방식이다.

깊은 복사를 위한 방법:
array.clone() 사용int[] a = {1, 2, 3};
int[] b = a.clone();
System.arraycopy() 사용int[] a = {1, 2, 3};
int[] b = new int[a.length];
System.arraycopy(a, 0, b, 0, a.length);
Arrays.copyOf() 사용int[] a = {1, 2, 3};
int[] b = Arrays.copyOf(a, a.length);
자바에서 제공하는 메서드는 성능적으로 최적화 되어 있어 직접 반복문으로 복사하는 것 보다 효율적이다.
장점:
단점:
0 - length - 1)를 벗어날 가능성이 존재함배열을 사용할 때에는 목적과 특성을 잘 고려하여 선택하고, 필요한 경우 컬렉션(ArrayList, LinkedList 등)을 사용하는 것이 좋을 수 있다.
참고) 컬렉션의 경우도 미리 저장될 자료의 크기를 알 수 있다면 Capacity를 지정해주는 것이 좋을 수 있다.