
참고
자바의 정석
https://doitnow-man.tistory.com/49
배열 (array)
배열이란?
- 같은 타입의 여러 변수를 하나의 묶음으로 다루는 것을 배열이라고 한다.
- 배열을 사용하면 많은 양의 데이터를 손쉽게 다룰 수 있다.
- 여기서 중요한 개념은 같은 타입이어야 한다는 것이다.
- 예를 들어 5명의 학생의 점수를 평균내야한다고 할 때 변수 5개를 선언하여 평균계산을 하는것은 너무 비효율적이다. 이럴때 배열을 사용하여 학생의 수가 늘어나도 유동적으로 처리할 수 있다.
int[] score = new int[5];
- 위의 코드를 그림으로 표현하면 아래와 같이 표현할 수 있다. 값을 저장할 수 있는 공간은 score[0]부터 score[4]까지 이며 변수 score는 배열을 다루는데 필요한 참조변수 일 뿐 값을 저장하기 위한 공간은 아니다. 또한 변수와 달리 배열은 각 저장공간이 연속적으로 배치되어 있다는 특징이 있다.

배열의 선언과 생성
- 배열의 선언 방법은 원하는 타입의 변수를 선언하고 변수 또는 타입의 배열임을 의미하는 대괄호 []를 붙이면 된다.
- 대괄호 []는 타입의 뒤에 붙여도 되고 변수의 이름 뒤에 붙여도 되지만 일반적인 경우 타입의 뒤에 붙이는것이 대세이다. 대괄호도 변수의 이름의 일부라기 보다는 타입의 일부라고 보기 때문이다.
| 선언 방법 | 선언 예 |
|---|
| 타입[] 변수이름; | int[] score; |
| 타입 변수이름[] | int score[] |
배열의 생성
- 배열을 선언하는 것은 단지 생성된 배얄을 다루기 위한 참조변수를 위한 공간이 만들어지는 것이며, 배열을 생성해야만 비로소 값을 저장할 수 있는 공간이 만들어 지는것이다.
- 배열을 생성하기 위해서는 new라는 연산자와 함께 사용된다.
타입[] 변수이름;
변수이름 = new 타입[길이]
- 쉽게 배열의 생성단계를 예시를 통해 살펴보면 아래와 같다.
- int[] score;
- int형 배열 참조변수 score를 선언. 데이터를 저장할 수 있는 공간은 아직 마련이 안되어 있음.
- score = new int[5];
- 연산자 new에 의해서 메모리의 빈공간에 5개의 int형 데이터를 저장할 수 있는 공간이 마련.
그리고 각 배열요소는 자동적으로 int의 기본 값 0으로 초기화.
끝으로 대입연산자 '='을 통해 배열의 주소가 int형 배열 참조변수 score에 할당.
배열의 길이와 인덱스
- 생성된 배열의 각 저장공간을 배열의 요소라고 하며, 배열의 이름[인덱스]의 형식으로 배열의 요소에 접근한다.
- 인덱스는 배열의 요소마다 붙여진 일련번호로 각 요소를 구별하며, 인덱스의 시작은 0부터 시작한다.
인덱스의 범위는 0부터 배열의 길이 - 1까지이다.
- 배열의 값을 저장하고 읽어오는 방법은 변수와 유사하다. 변수 이름 대신에 배열이름[인덱스]를 사용하면 된다.
- 배열의 또 다른 장점은 index로 상수 대신 변수나 수식도 사용할 수 있다.
- 배열을 다룰 때 한 가지 주의할 점은 index의 범위를 벗어난 값을 index로 사용하지 않아야 한다.
이러한 오류는 컴파일러 단계에서 걸러주지 못한다.
- 유효하지 않은 값을 index로 사용하면, 무사히 컴파일을 마쳤더라도 실행 시에 ArrayIndexOutOfBoundsException이 발생한다.
배열의 길이
- 배열의 길이란, 배열의 요소의 개수, 즉 값을 저장할 수 있는 공간의 개수이다.
- 배열의 길이는 양의 정수여야 하며, 최대 값은 int타입의 최대값인데, 그 만큼 배열을 생성하는 일은 매우 드문일이므로 거의 제약이 없다라고 알고 있어도 무방할 것 같다.
- 또한 아이러니하게 배열의 길이가 0인 배열도 생성이 가능하다.
int[] arr = new int[0];
- 배열의 길이가 0인 경우, 나중에 프로그래밍을 하다보면 매우 유용하게 쓸 일이 많다. 나중에 이런 상황이 나오면 언급을 한번 할 테니, 배열의 길이가 0이 될수 있다라고만 생각해보자.
배열이름.length
- 자바에서는 JVM이 모든 배열의 길이를 별도로 관리한다. 배열이름.length를 통해서 정보를 얻을 수 있다.
- 반환 값은 상수이며, 이 때문에, 값을 읽을 수만 있고 변경 할 수 없다.
- 배열을 이용할 때 for문을 자주 이용하는데, for 조건식의 분기점에 배열의 길이를 정수로 명시하는 것보단, 배열이름.length를 이용하는게 예외발생을 미연에 방지할 수 있다. for문 뿐만 아니라 다른데에서도 배열의 길이를 명시적으로 적는 것은 에러가 날 확률이 매우 높다.
배열의 길이 변경하기
- 위에서 배열의 길이는 변경 할 수 없다고는 했지만, 과연 정말 변경 할 수 없을까?
- 방법은 아래와 같다.
- 더 큰 배열을 새로 다시 생성한다.
- 기존 배열의 내용을 새로운 배열에 복사한다.
- 허나 이러한 작업들은 귀찮고 비용이 많이 들기 때문에 처음 선언 및 생성할 때 길이를 넉넉히 잡아야한다.
- 그렇다고 배열의 길이를 너무 크게 잡으면 메모리를 낭비할 수 있기 때문에 기존의 2배정도의 길이로 생성하는 것이 좋다.
배열의 초기화
- 배열은 생성과 동시에 자신의 타입의 기본값으로 초기화 되지만, 원하는 값으로 초기화 할려면 배열의 요소마다 접근하여 변수처럼 초기화를 진행해주면 된다.
int[] score = new int[5];
score[0] = 50;
score[1] = 60;
score[2] = 70;
score[3] = 80;
score[4] = 90;
- 또한 좀 더 편한 방법은 for문을 이용하는 방법이 있다.
for (int i = 0; i < score.length; i++) {
score[i] = i * 10 + 50;
}
- for문으로 배열을 초기화하려면 일정한 규칙이 있어야 가능하다. 그런데, 일정한 규칙이 없다면 어떻게 해야할까? 아래와 같이 진행하면 된다.
int[] score = new int[] {50, 60 ,70, 80, 90};
int[] score = {50, 60 ,70, 80, 90};
- new 타입[]을 위에 2번째 코드처럼 생략하여 더 간단하게 표현할 수 있다. 아무래도 생략된 형태의 코드가 더 간단하므로 자주 사용된다. 배열의 선언과 생성을 따로 하는 경우에는 생략할 수 없다는 점만 주의하면 된다.
- 또 자주 쓰이는 것은 아니지만 메서드의 파라미터로 배열을 받아야할 때, new 타입[]을 생략할 수 없다.
- {}안에 아무것도 넣지 않으면 길이가 0인 배열이 생성된다. 참조변수의 기본값은 null이지만, 배열을 가리키는 참조변수는 null대신 길이가 0인 배열로 초기화하기도 한다.
배열의 출력
- 배열을 초기화 할 때 for문을 사용하듯이, 배열에 저장된 값을 확인할 때도 for문을 이용하면 된다.
for (int i = 0; i < iArr1.length; i++) {
System.out.print(iArr1[i] + ",");
}
- 더 간단한 방법으로는 Arrays.toString(배열 이름) 메서드를 사용하는 것이다.
- 이 메서드는 배열의 모든 요소를 [첫번째 요소, 두번째 요소]와 같은 형식의 문자열로 만들어서 반환한다.
- 나중에 좀 더 자세한 내용을 다루고, 지금은 배열을 쉽게 출력하는 메서드다라고만 알고 있자.
- 만약 참조변수 자체를 출력하면 어떻게 될까? 상황에 따라 다르지만 일반적으로 배열의 주소가 출력된다. '타입@주소(16진수)'형식으로 출려된다. 하지만, 예외인 경우도 존재한다. 타입이 문자형인 경우 println 메서드를 사용할 때 문자 배열 그대로 출력된다.
배열의 복사
- 배열은 한번 생성하면 그 길이를 변경 할 수 없기 때문에 더 많은 저장공간이 필요하다면, 보다 큰 배열을 새로 만들고 이전 배열로부터 내용을 복사해야한다.
- 방법으로 2가지가 존재하는데 1번째 방법은 for문을 이용하는 방법이다.
int[] arr = new int[5];
int[] tmp = new int[arr.length * 2];
for (int i = 0; i < arr.length; i++) {
tmp[i] = arr[i];
}
arr = tmp;
- 이러한 작업은 꽤나 많은 비용이 발생하기 때문에 처음부터 배열의 길이를 넉넉히 잡아주는 것이 중요하다.
- 또한 배열의 길이를 너무 많이 잡아도 메모리의 낭비가 심하기 때문에 2배정도의 길이로 배열을 생성하는 것이 좋다.
참조
배열은 참조변수를 통해서만 접근할 수 있기 때문에, 자신을 가르키는 참조변수가 없는 배열은 사용할 수 없다.
이렇게 쓸모 없는 배열은 JVM의 GC가 자동적으로 메모리에 제거한다.
System.arraycopy()을 이용한 배열의 복사
- 2번째 방법으로 for문 대신에 System 클래스의 arraycopy()를 사용하면 보다 빠르게 배열을 복사 할 수 있다. for문은 배열의 요소 하나하나 복사하지만, System.arraycopy()는 지정된 범위의 값들을 한번에 처리한다. 즉, for문보다 효율적이다.
- 단, 주의할 점은 복사하려는 배열의 위치가 적절하지 못하여 복사하려는 내용보다 여유공간이 적으면 예외가 발생한다.
배열의 활용
- 총합과 평균
- 최대값과 최솟값
- 섞기 (shuffle)
- 임의의 값으로 배열 채우기
- 정렬하기
- 빈도수 구하기
임의의 값으로 배열 채우기
- 불연속적인 범위의 값들로 배열을 채우는 것은 어떻게 해야 할까?
- 정답은 배열을 1개 더 사용하면 된댜. 1번째 배열에 불연속적인 값들을 담고 임의로 선택된 index에 저장된 값으로 2번째 배열의 요소를 하나씩 채우면 된다.