intro : java 배열에 대한 개념을 알아보자.
배열 시작
배열이 필요한 이유
만약 학생의 점수를 출력해야하는 간단한 프로그램을 구성한다고 생각해보자. 각 학생이 추가될때마다 새로운 변수에 점수를 담고, 해당 점수를 출력을 하게되는데, 아직 배열에 대한 개념을 배우기 전이기 때문에 다음과 같은 코드를 통해 조금 힘들게 구성을 해야한다. 이렇게 같은 타입의 변수를 반복해서 선언하고 반복해서 사용하는 문제를 해결할수 있는게 배열이라는 개념이다.
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
형 타입으로 묶을수 있는데 다음과 같이 코드를 구성할 수 있다.
public class Array1Ref1 {
public static void main(String[] args) {
int[] students; // 배열 변수 선언
students = new int[5]; // 배열 생성
// 변수 값 대입
students[0] = 90;
students[1] = 80;
students[2] = 70;
students[3] = 60;
students[4] = 50;
// 변수 값 사용
System.out.println("학생1 점수: " + students[0]);
System.out.println("학생2 점수: " + students[1]);
System.out.println("학생3 점수: " + students[2]);
System.out.println("학생4 점수: " + students[3]);
System.out.println("학생5 점수: " + students[4]);
}
}
배열의 생성 단계
배열의 생성 단계에는 다음과 같은 단계를 따르는데 배열의 선언
, 배열 생성
, 배열 참조값 보관
을 따른다. 배열의 선언은 int[] students;
이처럼 내가 공통으로 묶고자 하는 타입을 [ ]
대괄호를 이용하여 묶고 변수를 선언하는 것을 말한다. 이후 해당 변수의 실제 생성 부분은 new
연산자를 이용해 new int[5]
배열의 사이즈를 지정한다. 이렇게 배열을 선언하고 생성하게되면 선언한 변수에 생성한 배열 참조값을 보관하게 된다. 참조값이란? 기존 변수 Chapter에서 배운 내용은 기본형 변수 타입 인데, 기본형 변수 타입을 제외한 모든 변수 타입은 참조형 변수 타입으로 주소값(참조값)
을 통해 접근할 수 있다.
배열 사용
인덱스
배열은 변수와 사용법이 비슷한데, 차이점이 있다면 다음과 같이 []
사이에 숫자번호를 넣어주면 된다. 배열의 위치를 나타내는 것을 index(인덱스)
라고 한다. 참고로 배열에서 인덱스는 1
이 아니라 0
부터시작한다. 만약 접근 가능한 배열의 인덱스 범위를 넘어가면 java.lang.ArrayIndexOutOfBoundsException
오류가 발생한다.
// 변수 값 대입
students[0] = 90;
students[1] = 80;
// 변수 값 사용
System.out.println("학생1 점수: " + students[0]);
System.out.println("학생2 점수: " + students[1]);
배열에 값 대입
배열에 값을 대입하던지 배열의 값을 사용하던지 일반적인 변수와 사용법은 같다. 추가로 []
를 통해 접근하고자 하는 배열의 인덱스 값만 넣어주면 된다.
students[0] = 90; // 1. 배열에 값을 대입
x001[0] = 90; // 2. 변수에 있는 참조값을 통해 실제 배열에 접근. 인덱스를 사용해서 해당 위치의 요소에 접근, 값 대입
students[1] = 80; // 1. 배열에 값을 대입
x001[1] = 80; // 2. 변수에 있는 참조값을 통해 실제 배열에 접근. 인덱스를 사용해서 해당 위치의 요소에 접근, 값 대입
배열 값 읽기
배열을 사용할때는 다음과 같이 참조값을 통해서 실제 배열에 접근하고 인덱스를 통해서 원하는 요소를 찾을 수 있다.
// 1. 변수 값 읽기
System.out.println("학생1 점수: " + students[0]);
// 2. 변수에 있는 참조값을 통해 실제 배열에 접근. 인덱스를 사용해서 해당 위치의 요소에 접근
System.out.println("학생1 점수: " + x001[0]); // students 변수의 주소값이 x001 가정
// 3. 배열의 값을 읽어옴
System.out.println("학생1 점수: " + 90);
기본형 vs 참조형
자바의 변수 데이터 타입을 가장 크게 보면 기본형과 참조형으로 분류할 수 있다. 사용하는 값을 직접 넣을 수 있는 기본
형, 그리고 방금 본 배열 변수와 같이 메모리의 참조값을 넣을 수 있는 참조형으로 분류할 수 있다. 기본형(Primitive Type): 우리가 지금까지 봤던 int
, long
, double
, boolean
처럼 변수에 사용할 값을 직접 넣을 수 있는 데이터 타입을 기본형(Primitive Type)이라 한다. 참조형(Reference Type): int[] students
와 같이 데이터에 접근하기 위한 참조(주소)를 저장하는 데이터 타입을 참조형(Reference Type)이라 한다. (위에서 살짝 언급한 내용을 다시 한번 정리한다.)
배열은 왜 참조형을 사용할까 ?
int
, long
, double
등 기본형 타입 변수들은 선언과 동시에 사이즈가 정해진다. int (4 Byte)
, long(8 Byte)
, double(8 Byte)
….. 배열은 생성시점에 동적으로 크기를 지정하게 되는데 예를들면 int[] array = new int[10]
인 경우는 배열의 사이즈가 int
타입이 10개 있기에 40 Byte
가 할당된다. 이렇게 참조형 타입을 사용하면 동적으로 크기를 설정할 수 있는 유연성을 제공 할 수 있고 복잡한 데이터 구조도 만들고 관리할 수 있는 장점이 생기기에 배열은 참조형을 사용한다.
배열 리펙토링
아래 코드를 보면 배열의 선언과 생성
부분에서 나왔던 코드랑은 굉장히 비교가 될 정도로 짧아지고 효율적인 코드를 작성할 수 잇게된다. 학생이 추가 될때마다 변수를 새로 생성하고, 출력문을 다시 작성했던것에 비해 아래 코드는 만약 학생이 추가될 경우 students 변수에 값을 하나 더 추가해주면 반복문을 통해 자동으로 새로 추가된 학생의 값 또한 출력 할 수 있게 된다.
public class Array1Ref4 {
public static void main(String[] args) {
//배열 생성 간략 버전, 배열 선언과 함께 사용시 new int[] 생략 가능
int[] students = {90, 80, 70, 60, 50};
for (int i = 0; i < students.length; i++) {
System.out.println("학생" + (i + 1) + " 점수: " + students[i]);
}
}
}
2차원 배열 - 시작
지금까지 학습한 배열은 단순히 순서대로 나열되어 있었다. 이것을 1차원 배열이라 한다. 이번에 학습할 2차원 배열은 이름 그대로 하나의 차원이 추가된다. 2차원 배열은 행과 열로 구성된다. 2차원 배열의 사용법은 []
가 하나 추가되는 것을 제외하고는 앞서본 1차원 배열과 같다. 아래 코드를 통해 2차원 배열에 대해서 알아보자.
public class ArrayDi0 {
public static void main(String[] args) {
// 2x3 2차원 배열을 만든다.
int[][] arr = new int[2][3]; // 행(row), 열(column)
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
위 2차원 배열에서의 코드를 보면 중복된 부분이 존재한다. 0행과 1행을 출력하는 코드의 내용을 자세히보면 결국 2차원 배열에서의 행과 열에 대한 인덱스를 순차적으로 접근하여 출력하면 된다는 것을 눈치 챌 수 있다. 아래 코드처럼 2중 반복문을 통해 순차적으로 2차원 배열의 인덱스를 활용하여 코드를 깔끔하게 작성할 수 있다.
public class ArrayDi2 {
public static void main(String[] args) {
// 2x3 2차원 배열을 만듭니다.
int[][] arr = new int[2][3]; // 행(row), 열(column)
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열
for (int row = 0; row < 2; row++) {
for (int column = 0; column < 3; column++) {
System.out.print(arr[row][column] + " ");
}
System.out.println(); // 한 행이 끝나면 라인을 변경한다.
}
}
}
2차원 배열 - 리펙토링2
리팩토링 1번에서의 부족한 부분을 조금더 찾아보면 배열의 선언과 초기화하는 부분에서 조금 아쉬운 부분이 존재한다, 2중 반복문에서 조건식에 해당하는 부분의 코드가 하드코딩으로 행과 열의 값 2
, 3
으로 작성되어 있는게 아쉽다. 배열은 동적으로 크기가 변할 수 있기 때문에 변경 포인트를 최대한 줄이는게 유지보수 측면에서도 좋기에 위 문제를 리팩토링하여 개선한 코드는 다음과 같이 작성할 수 있다.
public class ArrayDi3 {
public static void main(String[] args) {
// 2x3 2차원 배열, 초기화
// 배열의 생성시 new int[2][3] 대신에 다음과 같이 {} 를 이용해 직접 작성할 수 있다.
int[][] arr = {
{1, 2, 3},
{4, 5, 6}
};
// 2차원 배열의 길이를 활용
// 행과 열의 크기를 배열의 length 메소드를 통해 지정
for (int row = 0; row < arr.length; row++) {
for (int column = 0; column < arr[row].length; column++) {
System.out.print(arr[row][column] + " ");
}
System.out.println();
}
}
}
향상된 for문 (배열같은 순차적인 데이터에 접근해야할때 유용하다)
보통 for-each 문으로 부르며 향상된 for문은 기존의 반복문 보다 더 편리하게 사용할 수 있다. 물론 모든 상황에서 편리하게 사용할 수 있는건 아니지만 대부분의 상황에서는 향상된 for문을 사용한다. (index 값을 사용해야 하는 경우는 향상된 for문이 아니라, 기존에 사용하던 for문을 사용하자)
향상된 for문 정의
for (변수 : 배열 또는 컬렉션) {
// 배열 또는 컬렉션의 요소를 순회하면서 수행할 작업
}
향상된 for문 예제
public class EnhancedFor1 {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 4, 5};
//일반 for문
for(int i = 0; i < numbers.length; ++i) {
int number = numbers[i];
System.out.println(number);
}
//향상된 for문, for-each문
for (int number : numbers) {
System.out.println(number);
}
//for-each문을 사용할 수 없는 경우, 증가하는 index 값 필요
for(int i = 0; i < numbers.length; ++i) {
System.out.println("number" + i + "번의 결과는: " + numbers[i]);
}
}
}