배열 정리
배열을 쓰면 변수 하나에 값을 여러 개 담을 수 있다. 자바의 배열을 만들고 사용하는 방법을 간단하게 살펴보자.
배열 생성
배열을 만드는 방법은 몇 가지가 있다.
(1) 선언과 동시에 빈 배열 생성
int[] intArray = new int[5]; // 크기 5의 빈 배열
(2) 선언 후, 배열 생성
int[] intArray;
intArray = new int[5]; // 크기 5의 빈 배열
위 두 개는 사실 거의 똑같다고 볼 수 있다.
(3) 리터럴로 생성
int[] intArray = {1, 2, 3, 4, 5};
이렇게 하면 5개의 원소가 있으니까 intArray는 자동으로 크기 5의 배열이 된다.
그런데 이 방식은 변수를 정의할 때만 할 수 있다. 밑에 코드처럼 두 줄에 나누어서 하면 오류가 나온다.
int[] intArray;
intArray = {1, 2, 3, 4, 5}; // 오류
배열 사용
이제 배열을 사용하는 방법을 보자. 먼저 값을 대입하는 방법을 보도록 하겠다.
intArray[0] = 1;
intArray[1] = 2;
intArray[2] = 3;
intArray[3] = 4;
intArray[4] = 5;
이렇게 하면 0번 인덱스에는 정수 1을 넣어주고, 1번 인덱스에는 정수 2를 넣어주고, 이런 식으로 intArray 배열을 채우게 된다. 여기서 중요한 점: 인덱스는 0부터 시작한다! 5칸 짜리 배열이라면 인덱스가 0부터 4까지이다.
아래와 같이 범위에서 벗어나면
intArray[5] = 6;
런타임에 이런 에러가 나온다:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
그러니 배열을 사용할 때에는 인덱스를 조심히 다루어야겠다.
런타임?
런타임이란, 코드 작성 시점이 아니라 실제 실행될 때를 뜻한다. intArray[5] = 6; 을 적었을 때는 오류가 없다. 문법적으로 오류가 없기 때문이다. 그런데 실제 실행을 해서 접근하려고 하면 문제가 생기는 것이다. 강의 후반부에 예외처리를 배울 때 '컴파일 시점', '런타임 시점' 등에 대한 이야기를 더 깊게 나눠 보자.
변수명 뒤에 인덱스가 들어간다는 것 말고는 일반적인 변수와 사용법이 같다.
값을 대입할 때는 아까처럼:
intArray[0] = 1;
intArray[1] = 2;
값을 읽을 때는:
System.out.println(intArray[0] + intArray[1]); // 1 + 2
3
이렇게 사용할 수 있겠다.
앨리어싱(Aliasing)
이렇게 배열을 통째로 넘길 수도 있는데,
int[] arr1 = {1, 2, 3, 4, 5};
int[] arr2 = arr1;
아래 코드의 출력값은 뭘까?
arr1[0] = 100;
System.out.println(arr2[0]);
100
100이다. arr1을 arr2에 지정해줬을 때, 두 변수는 같은 주소를 가리키게 된다. 사실 arr1과 arr2는 아예 똑같은 값인 것이다. arr2를 arr1의 'Alias(가명)'이라고 할 수 있다.
그럼 만약 arr1을 arr2에 새롭게 복사하고 싶으면 어떻게 해야할까?
int[] arr1 = {1, 2, 3, 4, 5};
int[] arr2 = arr1.clone();
arr1[0] = 100;
System.out.println(arr1[0]);
System.out.println(arr2[0]);
100
1
이렇게 clone 라는 메소드를 사용하면 된다. 메소드의 사용은 나중에 천천히 배울테니 문법적인 어려움이 있어도 걱정하지 말고, '이런게 있구나' 정도만 확인하면 된다.
이렇게 배열이 복사가 된 것이라, arr1과 arr2는 서로 다른 배열이다. 그래서 arr1[0]을 수정해도 arr2[0]에는 영향을 미치지 않고, 1이 출력된다!
예제 1
100개 짜리 배열을 만들고 첫 번째 칸은 1, 두 번째 칸은 2, ..., 마지막 칸은 100으로 채워보자.
int[] intArray = new int[100];
for (int i = 0; i < 100; i++) {
intArray[i] = i + 1;
}
여기서 코드를 더 직관적으로 바꾸려면 100 대신 intArray.length를 쓰면 된다. length를 쓰면 우리가 배열의 크기를 몰라도 사용할 수 있고, 코드를 읽는 입장에서도 의미를 쉽게 해석할 수 있어서 좋다.
int[] intArray = new int[100];
for (int i = 0; i < intArray.length; i++) {
intArray[i] = i + 1;
}
위에서 만든 배열에 값이 제대로 들어갔는지 확인해 보자.
for (int i = 0; i < intArray.length; i++) {
System.out.println(intArray[i]);
}
1
2
3
4
...
99
100
배열이 아닌 일반 변수를 읽는 것과 거의 똑같다.
for-each
자바에는 'for-each'라는 문법이 있다. (파이썬에도 있었다.) 자바에서 for-each를 쓰는 방법이다.:
for (int i : intArray) {
System.out.println(i);
}
이렇게 쓰면, 처음에 수행 부분으로 들어갈 때 i는 intArray의 0번 인덱스의 값(원소)을 갖게 되고, 그 다음 들어갈 때는 1번 인덱스의 값(원소)을 갖게 되고... 이런 식으로 배열의 마지막 값(원소)까지 갖게 된다. 직접 확인해보자.
for (double i : intArray) {
System.out.println(i);
}
'형 변환' 강의에서 봤듯이, double에 int 값을 넣으면 자동으로 형 변환이 되기 때문에 위의 식처럼 써도 문제 없다.
예제 2
문자열을 담는 fruitsArray을 만든 후, 원소를 저장하고, for - each문을 활용하여 원소들을 출력해주었다.
String[] = fruitsArray = new String[5];
fruitsArray[0] = "딸기";
fruitsArray[1] = "당근";
fruitsArray[2] = "수박";
fruitsArray[3] = "참외";
fruitsArray[4] = "메론";
for (String fruit : fruitsArray) {
System.out.println(fruit);
}
딸기
당근
수박
참외
메론
실습과제: 배열 연습
(1) 크기가 30인 정수형 배열 intArray를 만들어라.
(2) 배열의 첫 번째(0번 인덱스) 칸부터 1001, 1002, 1003, ..., 1029, 1030을 순서대로 넣어라.
(3) 크기가 4인 문자열형 배열 remainders를 만들어 "Zero", "One", "Two", "Three"를 순서대로 넣어라.
(4) intArray 배열에 담긴 각 값을 4로 나눈 나머지를 인덱스로 생각하고, remainders 배열에서 그 인덱스에 위치한 단어를 출력해라. 이 때 반드시 '배열 정리' 노트에 있는, for- each문을 활용해라.
아래와 같은 출력 결과가 나올 것이다.
One
Two
Three
Zero
...
One
Two
public class Main {
public static void main(String[] args) {
// 여기에 코드를 작성하세요.
int[] intArray = new int[30];
for (int i = 0; i < intArray.length; i++) {
intArray[i] = 1000 + (i+1);
}
String[] remainders = {"Zero", "One", "Two", "Three"};
for (int i : intArray) {
System.out.println(remainders[i % 4]);
}
}
}
실습과제: DNA 염기 서열 분석
DNA 염기 서열은 생물의 유전 성질을 결정하는 매우 중요한 역할을 가지고 있다. 템플릿에 주어진 염기 서열에서 TAGG, CCAG, AGCC가 총 몇 번 등장하는지 세어보자.
만약 TAGG가 2번, CCAG가 4번, AGCC가 3번 등장한다면 아래와 같은 출력 값이 나온다:
TAGG: 2
CCAG: 4
AGCC: 3
힌트
문자열의 toCharArray() 메소드(함수)를 사용하면 char[] 배열을 얻을 수 있다.
char[] sequence = "abc".toCharArray();
반대로 char[] 배열을 문자열로 바꾸려면 이렇게 하면 된다:
String stringFromCharArr = new String(charArr);
TAGG: 1
CCAG: 12
AGCC: 15
public class Main {
public static void main(String[] args) {
String dna = "GATCCGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGTGTGAGCCA"
+ "CCACGCCCGGCTAATTTTTATTTATTTATTTAAAGACAGAGTCTCACTCT"
+ "GTCACTCAGGCTAGAGTGCAGTGGCACCATCTCAGCTCACTGCAGCCTTG"
+ "ACCTCCCTGGGCTCCGGTGATTTCACCCTCCCAAGTAGCTAGGACTACAG"
+ "GCACATGCCACGACACCCAGCTAATTTTTTATTTTCTGTGAAGTCAAGGT"
+ "CTTGCTACGTTGCCCATGCTGGTATCAAACCCCTGGGCTCAATCAATCCT"
+ "TCCACCTCAGCCTCCCCAAGTATTGGGGTTACAGGCATGAGCTACCACAC"
+ "TCAGCCCTAGCCTACTTGAAACGTGTTCAGAGCATTTAAGTTACCCTACA"
+ "GTTGGGCAAAGTCATCTAACACAAAGCCCTTTTTATAGTAATAAAATGTT"
+ "GTATATCTCATGTGATTTATTGAATATTGTTACTGAAAGTGAGAAACAGC"
+ "ATGGTTGCATGAAAGGAGGCACAGTCGAGCCAGGCACAGCCTGGGCGCAG"
+ "AGCGAGACTCAAAAAAAGAAAAGGCCAGGCGCACTGGCTCACGCCTGTAA"
+ "TCCCAGCATTTCGGGAGGCTGAGGCGGGTGGATCACCTGAGGTCAGGAGT"
+ "TCAAGACCAGCCTAGCCAACATGGTGAAACCCCGTCTCTACTAAAATACA"
+ "AAAATTAACCGGGCGTGATGGCAGGTGCCTGTAATCCCAGCTACTTGGGA"
+ "GGCTGAGGCAGGAGAATCGCTTGAACCAGGAGGCGGAGGTTGCAGGGAGC"
+ "CAAGATGGCGCCACTGCACTCCAGCCTGGGCGATAGAGTGAGACTCCGTC"
+ "TCAGAAAAAAAAGAAAAGAAACGAGGCACAGTCGCATGCACATGTAGTCC"
+ "CAGTTACTTGAGAGGCTAAGGCAGGAGGATCTCTTGAGCCCAAGAGTTTG"
+ "AGTCCAGCCTGAACAACATAGCAAGACATCATCTCTAAAATTTAAAAAAG"
+ "GGCCGGGCACAGTGGCTCACACCTGTAATCCCAGCACTTTGGGAGGTGGA"
+ "GGTGGGTAGATCACCTGACGTCAGGAGTTGGAAACCAGCCTGGCTAACAT";
char[] charArray = dna.toCharArray();
// TAGG, CCAG, AGCC
int tagg = 0, ccag = 0, agcc = 0;
char[] current = new char[4];
for (int i = 0; i < charArray.length - 3; i++) {
for (int j = 0; j < current.length ; j++) {
current[j] = charArray[i + j];
}
// char[]을 String으로 변환
// 예: ['a', 'b', 'c', 'd'] => "abcd"
String seq = new String(current);
switch (seq) {
case "TAGG":
tagg++;
break;
case "CCAG":
ccag++;
break;
case "AGCC":
agcc++;
break;
}
}
// 테스트
System.out.println("TAGG: " + tagg);
System.out.println("CCAG: " + ccag);
System.out.println("AGCC: " + agcc);
}
}
TAGG: 1
CCAG: 12
AGCC: 15

다중 배열
동일한 자료형 여러 개를 묶어 사용하기 위해 배열을 사용한다.
int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
위의 배열은 정수 자료를 아래처럼 보관하고 있다.
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
혹은 세로로 볼 수도 있다.
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
다중 배열
그렇다면 2차원 구조는 배열로 어떻게 나타낼 수 있을까?
1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 |
'다중 배열'을 선언하면 된다.
int[][] multiArray;
위 표의 내용으로 초기값을 바로 설정하기 위해서는 이렇게 써야 한다.
int[][] multiArray = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
'int[4] 배열 세 개가 묶인 배열'이라고 볼 수 있다. 즉, multiArray[0]의 자료형은 int[4]이고 내용은 {1, 2, 3, 4}인 것이다.
생성
위에서는 배열의 초기값을 바로 설정해주었는데, 만약 선언과 생성만 하기 위해서는 어떻게 해야 할까?
3x4 사이즈의 빈 배열을 만들어보자.
int[][] multiArray = new int[3][4];
각 대괄호 사이에 사이즈를 넣어준다. 일반적으로 '행(줄)'을 첫 번째 대괄호에, '열(칸)'을 두 번째 대괄호에 넣는다.
사용
앞서 보았듯, multiArray[0]은 이제 int[4]의 자료형을 갖게 된다. 마찬가지로 multiArray[1], multiArray[2] 모두 int[4]의 자료형을 갖게 된다. 그렇기 때문에 multiArray[0]을 일반적인 배열 탐색법으로 탐색할 수 있다.
for (int i = 0; i < multiArray[0].length; i++) {
multiarray[0][i] = 1 + i;
}
마찬가지 방법으로 위의 표 내용처럼 multiArray를 이렇게 채울 수 있다.
for (int i = 0; i < multiArray[0].length; i++) {
multiarray[0][i] = 1 + i;
}
for (int i = 0; i < multiArray[1].length; i++) {
multiarray[1][i] = 5 + i;
}
for (int i = 0; i < multiArray[2].length; i++) {
multiarray[2][i] = 9 + i;
}
중첩 반복문(Nested Loops)
하지만 위의 방법도 너무 반복적이다. 중첩 반복문을 사용하면 깔끔하게 쓸 수 있다.
for (int i = 0; i < multiArray.length; i++) {
for (int j = 0; j < multiArray[i].length; j++) {
multiArray[i][j] = (i * 4 + 1) + j;
}
}
여기서 multiArray.length는 전체 자리 수 12가 아닌, 행(줄)의 수인 3이다.
'~2023.02 > Java' 카테고리의 다른 글
자바 기초 _ [토픽2] 자바 객체 지향 프로그래밍 _ 객체 설계하기 (0) | 2021.12.30 |
---|---|
자바 기초 _ [토픽2] 자바 객체 지향 프로그래밍 _ 객체 만들기 (0) | 2021.12.29 |
자바 기초 _ [토픽1] 자바 왕기초 _ 조건문과 반복문 (0) | 2021.12.29 |
자바 기초 _ [토픽1] 자바 왕기초 _ 변수와 연산 (0) | 2021.12.26 |
자바 기초 _ [토픽1] 자바 왕기초 _ Hello, Java! (0) | 2021.12.25 |