배열은 아래 그림과 같이 같은 자료형의 데이터를 일렬로 묶어놓은 것을 의미한다.
예를 들어 보도록 하자.
만약 100명의 학생의 평균 점수를 저장하기 위해서는 어떻게 해야 하는가?
기존의 방식대로 저장을 한다면 다음과 같이 저장해야 할 것이다.
float student1, student2, student3.... student100;
student1=학생1 점수;
student2=학생2 점수;
...
student100=학생100 점수;
위의 코드와 같이 작성한다면 학생 수가 늘어남에 따라 상당히 관리하기 까다롭고, 복잡한 코드가 될 것이다.
이러한 문제를 방지하기 위해 배열을 선언해서 사용하면 매우 간결하게 많은 학생의 평균 점수를 관리할 수 있다.
배열은 아래 그림과 같이 메모리상에 일렬로 할당이 된다.
배열이 생성이 되면 위의 그림과 같이 메모리상에 순서대로 할당이 되는 특징이 있다. 정확히는 배열의 이름은 stack
영역에, 배열의 데이터는 heap
영역에 할당이 된다.
배열의 선언은
이러한 형식의 배열을 사용할 것이다.
라고 프로그램에 알리는 것을 의미한다.
이러한 배열의 선언은 다음과 같이 2가지 방식으로 할 수 있다.
배열의 선언:
1.자료형[] 배열_이름;
2.자료형 배열_이름[];
예를 들어 int형 배열을 선언하기 위해서는 다음과 같이 두가지 방식으로 선언할 수 있다.
int[] arr;// 첫번째 방법
int arr[];// 두번재 방법
이와 같이 두 가지 방법 중에서 선택해서 작성을 하면 프로그램에서 "이러한 형식의 배열을 사용할 것이다" 라고 인식하면서 배열이 선언이 된다.
이렇게 배열을 선언을 하면 배열의 이름(선언한 변수명)은 메모리의 stack
영역에 할당이 되며, 이 배열의 이름은 배열이 생성될때 heap
영역에서의 배열의 주소를 저장할 수 있다.
배열을 선언한 이후에는 실제로 배열을 메모리에 할당해서 데이터를 저장
할 수 있도록 배열을 생성
해야 한다.
배열의 생성의 경우 아래와 같이 new
키워드를 이용해 생성할 수 있다.
배열_이름 = new 자료형[배열_크기];
만약 배열 이름이 score
이고, 자료형은 float
일때, 100명의 학생의 점수를 저장하는 배열은 다음과 같이 선언할 수 있다.
score = new float[100];
이렇게 하면 아래 그림과 같이 배열이 생성이 되면서 메모리의 heap
영역에 공간을 할당하고, 배열을 사용할 수 있도록 연결한다.
실제로 배열을 생성 및 선언하기 위해서는 다음과 같이 두 가지 방식으로 배열을 생성 및 선언할 수 있다.
- 선언과 동시에 생성
int arr[]=new int[10];
- 선언 후 생성
int arr[];
arr=new int[10];
이를 이용해 100명의 학생의 평균 점수를 저장하기 위해서는 다음과 같이 선언할 수 있다.
float mean[] = new float[100];
float mean[];
mean = new float[100];
이와 같은 방법으로 배열을 선언 및 생성해서 사용할 수 있다.
배열의 indexing이란 배열의 요소에 접근해서 사용하는 것을 의미한다.
배열을 본격적으로 사용하기 위해서는 배열의 indexing에 대해서 알아야 한다.
위에서 설명한 바와 같이 배열의 indexing이란 배열의 요소에 접근해서 사용하는 것으로, 본격적으로 배열을 선언 및 생성 후, 배열에 접근해서 데이터를 넣고, 수정하고, 삭제하는 연산을 할 수 있도록 하는 것이 바로 배열의 indexing 이다.
배열의 indexing을 하기 위해 명심해야 할 점이 있다.
배열의 시작은 0부터 이다.
배열은 무조건적으로 0번째 부터 시작한다. 즉, 크기가 N만큼의 배열이 생성됬다 가정하면 0번째 부터 N-1번째 까지 총 N개의 변수가 생성됨을 의미한다.
이는 배열에 접근할때 배열의 시작주소를 기준으로 offset을 하면서 접근을 하기 때문이다.
예를들어 offset이 0인 경우 배열의 시작 주소이자, 배열의 첫번째 요소를 가리키며, offset이 1인 경우 배열의 시작주소+(자료형크기*offset)이
되면서 배열의 2번째 요소를 가리키게 된다.
즉, 크기가 10인 배열의 경우 0~9번째 까지 접근할 수 있다는 것이다.
이때 접근하는 번호(0번째, 1번째 등..)을 index
라고 한다.
배열 접근 방법은 다음과 같다.
배열 저장
arr[idx]=data;
배열 읽기
val=arr[idx];
이때, idx
란 index
의 약자로, 앞에서 설명했던 접근할 수 있는 배열의 접근 번호이다.
즉, 크기가 10인 배열의 경우 index는 0~9 사이의 정수가 된다.
직접 간단한 실습을 통해 한번 알아보도록 하자.
학생 10명의 점수를 입력받아 저장하고, 출력하는 코드를 작성해 보자.
먼저, Scanner
를 이용해 학생의 점수를 입력받는 부분을 작성하면 다음과 같다.
import java.util.Scanner;
public class array {
public static void main(String[] args) {
int data;
int i;
Scanner input= new Scanner(System.in);// scanner class 생성
for(i=0; i<10; i++)
data=input.nextInt();// 입력받기
}
}
다음으로, 배열을 생성하면 다음과 같다.
import java.util.Scanner;
public class array {
public static void main(String[] args) {
int data;
int i;
int score[] = int[10];// 배열 생성
Scanner input= new Scanner(System.in);// scanner class 생성
for(i=0; i<10; i++)
data=input.nextInt();// 입력받기
}
}
다음으로 입력받은 값을 배열로 저장을 하면 다음과 같다.
import java.util.Scanner;
public class array {
public static void main(String[] args) {
int data;
int i;
int score[] = int[10];// 배열 생성
Scanner input= new Scanner(System.in);// scanner class 생성
for(i=0; i<10; i++){
data=input.nextInt();// 입력받기
score[i]=data;// 배열에 값 저장
}
}
}
이때, 배열의 시작은 0이며, 마지막은 9까지 이며, i 역시 0~9까지 1씩 증가해 총 10번 동작하므로, 배열의 index는 i가 된다.
마지막으로, 배열에 있는 값을 출력하는 코드를 작성하면 다음과 같다.
import java.util.Scanner;
public class array {
public static void main(String[] args) {
int data;
int i;
int score[] = int[10];// 배열 생성
Scanner input= new Scanner(System.in);// scanner class 생성
for(i=0; i<10; i++){
data=input.nextInt();// 입력받기
score[i]=data;// 배열에 값 저장
}
for(i=0; i<10; i++)
System.out.printf("score[%d] is %d\n", i, score[i]);// 배열 값 출력
}
}
또한, 배열의 길이의 경우 배열이름.length
을 통해 알 수 있다.
이를 이용해 코드를 수정하면 다음과 같다.
import java.util.Scanner;
public class array {
public static void main(String[] args) {
int data;
int i;
int score[] = new int[10];// 배열 생성
Scanner input= new Scanner(System.in);// scanner class 생성
for(i=0; i<score.length; i++){
data=input.nextInt();// 입력받기
score[i]=data;// 배열에 값 저장
}
for(i=0; i<score.length; i++)
System.out.printf("score[%d] is %d\n", i, score[i]);// 배열 값 출력
}
}
이와 같이 배열의 값을 입출력 할 수 있으며, 배열의 길이를 배열이름.length
형식으로 작성할 경우 추후 배열의 크기에 변동이 있다 해도 배열 생성부분만 바꿔주면 되기 때문에 효율적인 코드를 작성할 수 있다.
java에서 배열은 생성과 동시에 자신의 자료형에 따른 기본값으로 초기화가 되므로 별도로 배열을 초기화 하지 않아도 된다.
예를 들어 int
형 배열을 선언했을 경우 배열의 요소는 전부 0으로 초기화 된다.
그러나, 특정한 값으로 초기화를 하고자 할 때는 다음과 같은 방법으로 초기화를 할 수 있다.
먼저 값을 일일히 대입하면서 초기화 하는 방법에 대해 알아보자.
값을 일일히 대입해서 초기화 하는것은 말 그대로 배열의 모든 요소에 특정한 값을 대입해서 초기화를 하는 것을 의미한다.
예를 들어보자.
만약 크기가 5인 배열에 10, 20, 30, 40, 50 이라는 값을 대입해서 초기화를 진행한다 가정하자.
이때, 값을 일일히 대입하면서 초기화를 진행하는 방법은 다음과 같다.
public class array {
public static void main(String[] args) {
int data[] = new int[5];// 배열 생성
/*배열 값 대입(초기화)*/
data[0]=10;
data[1]=20;
data[2]=30;
data[3]=40;
data[4]=50;
}
}
이와 같은 방법을 이용하면 배열의 각 요소에 저장되는 값을 직관적으로 알 수 있다는 장점이 있으나, 코드가 길어지면서 가독성이 떨어질 수 있다는 단점이 있다.
다음으로 반복문을 이용해 값을 대입하는 방법이다.
이때, 반복문을 이용하기 위해서는 배열에 저장되는 데이터의 일정한 규칙이 존재해야만 가능하다는 제약사항이 있다.
위 조건의 경우, 배열의 주소가 1씩 증가함에 따라 값이 10부터 시작해서 10씩 증가하는 규칙이 있다.
이를 기반으로 반복문을 이용해 초기화를 하면 다음과 같다.
public class array {
public static void main(String[] args) {
int data[] = new int[5];// 배열 생성
int i;
int val=10;
/*배열 값 초기화*/
for(i=0; i<data.lentgh; i++){
data[i]=val;
val+=10;
}
}
}
다음으로 생성과 동시에 배열을 초기화 하는 방법이다.
생성과 동시에 초기화 하기 위해서는 다음과 같이 new
키워드를 사용하는 방법과 new
키워드 없이 초기화 하는 방법이 있다.
public class array {
public static void main(String[] args) {
int data1[] = new int[] {10, 20, 30, 40, 50};// 배열 생성 및 초기화1(new 키워드 사용)
int data2[] = {10, 20, 30, 40, 50};// 배열 생성 및 초기화2(new 키워드 사용x)
}
}
배열의 출력중 하나는 java.util.Arrays
를 import하고 Arrays.toString()
를 사용해 출력하는 방법이 있다.
사용 방법은 다음과 같다.
import java.util.Arrays;
public class Array {
public static void main(String[] args) {
int num[] = {10, 50, 30, 20, 40};
System.out.println(Arrays.toString(num));
}
}
output
[10, 50, 30, 20, 40]
배열은
for-each
문을 사용해 출력을 할 수 있다.
for-each
의 문법 구조는 다음과 같다.
for(변수:배열)
예를 들어 배열 arr
의 합계를 구한다면 기존에는 다음과 같이 작성을 해야 했다.
int arr[] = new int {1,2,3,4,5,6};
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
System.out.println("합계 : "+sum);
그러나, for-each
구문을 이용하면 다음과 같이 간소하게 작성할 수 있다.
int arr[] = {1,2,3,4,5,6};
int sum = 0;
for(int x : arr)
sum += x;
System.out.println("합계 : "+sum);
배열에 대해서 알아보면서 한가지 배열의 한계를 찾을 수 있었을 것이다. 바로 배열의 크기는 고정되 있다
라는 한계점이다.
즉, 100명의 학생의 점수를 저장하는 배열을 선언했으나, 추후 200명의 학생이 입학한 경우에는 코드를 수정해서 다시 배포해야 한다.
즉, 프로그램 내에서 자유롭게 배열의 크기를 늘리는 것이 아니라, 다시 코드를 작성해서 수정된 프로그램을 다운로드 받도록 해야 한다는 것이다.
또한, 출산율 저하로 인해 학생이 30명만 입학했다고 가정하면 총 100명을 저장할 수 있는 프로그램에서 30명만 사용하게 되므로 메모리가 낭비가 된다.
이러한 문제를 해결하기 위해 자유롭게 변수의 크기를 조절하는 List
라는 개념이 존재한다. 즉, List
라는 것을 이용하면 학생이 200명이 입학하면 메모리의 크기를 늘려 점수를 전부 저장할수 있고, 학셍이 30명만 입학하면 메모리를 줄여 30명만 저장할 수 있는 변수를 사용할 수 있다. 이러한 List
라는 개념은 어려울 수 있으므로 추후에 다룰 예정이다.
어쨌든, 이러한 List
라는 개념이 있음에도 불구하고 배열을 배우는 이유는 그럼에도 배열의 접근 속도가 빠르기 때문에 여전히 많이 사용되며, 무엇보다 연속된 데이터를 다루는 능력
을 기르는데 큰 도움이 된다.
실제로 인터넷 등 각종 통신할때 주고받는 데이터들은 패킷(packet)
이라 불리며, 배열과 같이 일정한 크기의 연속된 데이터들로 구성되 있다. 우리가 네이버에 들어가고, 검색을 할 때 역시 이러한 패킷
이라는 것 안에 데이터를 넣어서 주고받아 우리가 검색, 로그인, 쇼핑 등을 할 수 있게 된다.
이러한 데이터 전송을 위한 패킷을 만들고, 수정하고, 읽는 과정은 배열에서 값을 수정하고, 읽고, 만드는 과정과 동일한 알고리즘을 사용하기 때문에 유사점이 많이 존재한다.
또한, 연속된 데이터를 제어할때 사용되는 알고리즘은 배열에서 사용되는 알고리즘과 상당히 유사하기 때문에 배열을 공부한다는 것 자체가 추후 자주 사용될 연속된 데이터
를 다루기 위한 기초를 쌓는다는 부분에서 배열을 다루는 능력을 배운다는 것 자체는 상당히 유의미하다.