[JAVA/자바] 배열
배열이 필요한 이유
학생의 점수를 출력하는 간단한 프로그램을 작성해 보자.
package array;
public class Array1 {
public static void main(String[] args) {
int student1 = 90;
int student2 = 80;
int student3 = 70;
int student4 = 60;
int student5 = 50;
System.out.println("학생1 점수: " + student1);
System.out.println("학생2 점수: " + student2);
System.out.println("학생3 점수: " + student3);
System.out.println("학생4 점수: " + student4);
System.out.println("학생5 점수: " + student5);
}
}
- 학생을 몇 명 더 추가해야 한다면 변수를 선언하는 부분과 점수를 출력하는 부분의 코드도 추가해야 한다.
학생을 몇 명 더 추가하는 것은 개발자가 코딩으로 해결할 수 있겠지만, 학생을 수백 명 이상 추가해야 한다면 코드가 상당히 많이 늘어날 것이다.
결국 학생 수가 증가함에 따라 코딩 양이 비례해서 증가하는 문제가 발생한다.
- 변수를 선언하는 부분을 보면 학생 수가 증가함에 따라 int 형 변수를 계속해서 추가해야 한다.
학생 수가 5명이면 int 형 변수를 5개 선언해야 하고, 학생 수가 100명이라면 int 형 변수를 100개 선언해야 한다.
결국 비슷한 변수를 반복해서 선언하는 문제가 발생한다.
- 반복문으로 해결할 수 있을 것 같지만, 점수를 출력하는 부분을 보면 변수의 이름이 다르기 때문에 반복문도 적용할 수 없다.
이렇게 같은 타입의 변수를 반복해서 사용하는 문제를 해결하는 것이 바로 배열이다.
배열의 선언
1. int[] students; // 배열 변수 선언
- 배열을 사용하려면 int[ ] students;와 같이 배열 변수를 선언해야 한다.
- 일반적인 변수와 차이점은 int[ ]처럼 타입 다음에 대괄호( [ ] )가 들어간다는 점이다.
- 배열 변수를 선언한다고 해서 아직 사용할 수 있는 배열이 만들어진 것은 아니다!
* int a에는 정수를, double b에는 실수를 담을 수 있다.
* int[ ] students와 같은 배열 변수에는 배열을 담을 수 있다. ( 배열 변수에는 10, 20 같은 값이 아니라 배열이라는 것을 담을 수 있다.)
배열 생성
2. students = new int[5]; // 배열 생성
- 배열을 사용하려면 배열을 생성해야 한다.
- new int[5]라고 입력하면 총 5개의 int형 변수가 만들어진다.
- new는 새로 생성한다는 뜻이고, int[5]는 int형 변수 5개라는 뜻이다. 따라서 int형 변수 5개를 다룰 수 있는 배열을 새로 만든다는 뜻이다.
- 앞서 int student1, int student2, ... int student5까지 총 5개의 변수를 직접 선언했다. 배열을 사용하면 이런 과정을 한 번에 깔끔하게 처리할 수 있다.
배열 초기화
- new int[5]라고 하면 총 5개의 int 형 변수가 만들어진다. 자바는 배열을 생성할 때 그 내부값을 자동으로 초기화한다.
- 숫자는 0, boolean은 false, String은 null(없다는 뜻이다)로 초기화된다.
배열 참조값 보관
3. students = x001; // 배열 참조값 보관
- new int[5]로 배열을 생성하면 배열의 크기만큼 메모리를 확보한다
* int 형을 5개 사용하면 4byte * 5 -> 20byte를 확보한다.
- 배열을 생성하고 나면 자바는 메모리 어딘가에 있는 이 배열에 접근할 수 있는 참조값(주소) (x100)을 반환한다.
* 여기서 x001이라고 표현한 것이 참조값이다. (실제로 x001처럼 표현되는 것은 아니고 이해를 돕기 위한 예시이다.)
- 앞서 선언한 배열 변수인 int[ ] students에 생성된 배열의 참조값(x001)을 보관한다.
- int[ ] students 변수는 new int[5]로 생성한 배열의 참조값을 가지고 있다.
* 이 변수는 참조값을 가지고 있다. 이 참조값을 통해 배열을 참조할 수 있다. 쉽게 이야기해서 참조값을 통해 메모리에 있는 실제 배열에 접근하고 사용할 수 있다.
* 참고로 배열을 생성하는 new int[5] 자체에는 아무런 이름이 없다! 그냥 int 형 변수를 5개 연속으로 만드는 것이다.
따라서 생성한 배열에 접근하는 방법이 필요하다. 따라서 배열을 생성할 때 반환되는 참조값을 어딘가에 보관해두어야 한다.
앞서 int[ ] students 변수에 참조값(x001)을 보관해 두었다. 이 변수를 통해서 이 배열에 접근할 수 있다.
이 부분을 풀어서 설명하면 다음과 같다.
int[] students = new int[5]; // 1. 배열 생성
int[] students = x001; // 2. new int[5]의 결과로 x001 참조값 반환
students = x001 // 3. 최종 결과
배열 사용
인덱스
배열은 변수와 사용법이 비슷한데, 차이점이 있다면 다음과 같이 [ ] 사이에 숫자 번호를 넣어주면 된다.
배열의 위치를 나타내는 숫자를 인덱스(index)라 한다.
배열은 0부터 시작한다
new int[5]와 같이 5개의 요소를 가지는 int 형 배열을 만들었다면 인덱스는 0, 1, 2, 3, 4 가 존재한다.
여기서 주의해야 할 점이 있는데 인덱스는 0부터 시작한다는 것이다.
배열의 요소를 5개로 생성했지만, 인덱스는 0부터 시작한다.
따라서 사용 가능한 인덱스의 범위는 0~(n-1)이 된다. 그래서 students[4]가 배열의 마지막 요소이다
만약 students[5]와 같이 접근 가능한 배열의 인덱스 범위를 넘어가면 다음과 같은 오류가 발생한다.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
at array
배열에 값 대입
배열에 값을 대입하든 배열의 값을 사용하든 간에 일반적인 변수와 사용법은 같다. 추가로 [ ]를 통해 인덱스만 넣어주면 된다.
students[0] = 90; // 1. 배열에 값을 대입
x001[0] = 90; // 2. 변수에 있는 값을 참조값을 통해 실제 배열에 접근. 인덱스를 사용해서 해당 위치의 요소에 접근, 값 대입
배열 값 읽기
// 1. 변수 값 읽기
System.out.println("학생1 점수: " + students[0]);
// 2. 변수에 있는 참조값을 통해 실제 배열에 접근. 인덱스를 사용해서 해당 위치의 요소에 접근
System.out.println("학생1 점수: " + x001[0]);
// 3. 배열의 값을 읽어옴
System.out.println("학생1 점수: " + 90);
배열을 사용하면 이렇게 참조값을 통해서 실제 배열에 접근하고 인데스를 통해서 원하는 요소를 찾는다.
기본형 vs 참조형
자바의 변수 데이터 타입을 가장 크게 보면 기본형과 참조형으로 분류할 수 있다.
사용하는 값을 직접 넣을 수 있는 기본형, 그리고 배열 변수와 같이 메모리의 참조값을 넣을 수 있는 참조형이 있다.
- 기본형(Primitive Type) : int, long, double, boolean처럼 변수에 사용할 값을 직접 넣을 수 있는 데이터 타입을 기본형이라 한다.
- 참조형(Reference Type) : int[ ] students와 같이 데이터에 접근하기 위한 참조(주소)를 저장하는 데이터 타입을 참조형이라 한다. 객체나 클래스를 담을 수 있는 변수들도 모두 참조형이다.
*참고
- 기본형은 선언과 동시에 크기가 정해진다. 따라서 크기를 동적으로 바꾸거나 할 수는 없다.
반면에 배열과 같은 참조형은 크기를 동적으로 할당할 수 있다.
예를 들어서 Scanner를 사용해서 사용자 입력에 따라 size 변수의 값이 변하고, 생성되는 배열의 크기도 달라질 수 있다.
이런 것을 동적 메모리 할당이라 한다. 기본형은 선언과 동시에 사이즈가 정적으로 정해지지만,
참조형을 사용하면 이처럼 동적으로 크기가 변해서 유연성을 제공할 수 있다.
- 기본형은 사용할 값을 직접 저장한다. 반면에 참조형은 메모리에 저장된 배열이나 객체의 참조를 저장한다.
이로 인해 참조형은 더 복잡한 데이터 구조를 만들고 관리할 수 있다. 반면 기본형은 더 빠르고 메모리를 효율적으로 처리한다.
2차원 배열
단순히 순서대로 나열되어 있는 것을 1차원 배열이라 한다.
2차원 배열은 행과 열로 구성된다.
2차원 배열은 int[ ][ ] arr = new int[2][3]와 같이 선언하고 생성한다.
그리고 arr[1][2]와 같이 사용하는데, 먼저 행 번호를 찾고, 그다음에 열 번호를 찾으면 된다.
행은 영어로 row(로우), 열은 영어로 column(컬럼)이라 한다.
2차원 배열의 사용법은 [ ]가 하나 추가되는 것을 제외하고는 1차원 배열과 같다.
package array;
public class ArrayDi0 {
public static void main(String[] args) {
// 2x3 2차원 배열을 만든다.
int[][] arr = new int[2][3]; // 행 2, 열 3
arr[0][0] =1; // 0행, 0열
arr[0][1] =2; // 0행, 1열
arr[0][2] =3; // 0행, 2열
arr[1][0] =4; // 1행, 0열
arr[1][1] =5; // 1행, 1열
arr[1][2] =6; // 1행, 2열
// 0행 출력
System.out.print(arr[0][0] + " "); // 0열 출력
System.out.print(arr[0][1] + " "); // 1열 출력
System.out.print(arr[0][2] + " "); // 2열 출력
System.out.println(); // 한 행이 끝나면 라인을 변경한다.
// 1행 출력
System.out.print(arr[1][0] + " "); // 0열 출력
System.out.print(arr[1][1] + " "); // 1열 출력
System.out.print(arr[1][2] + " "); // 2열 출력
System.out.println();
}
}
- 이 코드는 2차원 배열을 만들고, 배열에 값을 1부터 6까지 순서대로 직접 입력한다.
- 다음과 같은 결과를 만들기 위해 0행에 있는 0, 1, 2열을 출력한다. 그리고 다음으로 1행에 있는 0, 1, 2열을 출력한다.