배열은 같은 타입의 데이터를 연속된 공간에 나열하고, 각 데이터에 인덱스를 부여해놓은 자료구조이다.
int score1 = 83;
int score2 = 90;
int score3 = 87;
.
.
.
int score30 = 75;
위의 데이터는 다음과 같이 배열로 생성할 수 있다.
score 배열의 각 인덱스는 각 항목의 데이터를 읽거나 저장하는 데 사용되며 아래와 같이 배열 이름 옆에 대괄호 []
에 기입된다. 그리고 인덱스는 0부터 시작한다.
score[인덱스]
int 배열은 int 값만 저장 가능하고, String 배열은 문자열만 저장 가능하다.
또한 선언과 동시에 저장할 수 있는 타입이 결정된다.
만약, 다른 타입의 값을 저장하려고 하면 타입 불일치(Type mismatch)
컴파일 에러가 발생한다.
3개의 값을 저장하는 배열을 생성했다고 가정해보자.
프로그램 실행 도중에 5개의 값을 저장하는 배열로 수정할 수 없고, 반대로 2개의 값만 저장하는 배열로 수정할 수도 없다.
만약, 5개의 값을 저장해야하는 경우가 발생한다면 길이 5의 새로운 배열을 생성하고, 기존 배열 항목을 새 배열로 복사해야 한다.
배열을 사용하기 위해서는 배열 변수를 먼저 선언해야 하는데, 배열 변수 선언은 두 가지 형식으로 작성할 수 있다.
형식1: 타입[ ] 변수;
형식2: 타입 변수[ ];
대괄호[]
는 배열 변수를 선언하는 기호로 사용되는데, 타입 뒤 혹은 변수 뒤에 붙을 수 있다.
int[] intArray;
double[] doubleArray;
String[] strArray;
int intArray[];
double doubleArray[];
String strArray[];
배열 변수는 참조 변수에 속한다. 배열도 객체이므로 힙 영역에 생성되고 배열 변수는 힙 영역의 배열 객체를 참조하게 된다.
참조할 배열 객체가 없다면 배열 변수는 null 값으로 초기화될 수 있다.
만약 배열 변수가 null 값을 가진 상태에서 변수[인덱스]
로 값을 읽거나 저장하게 되면 NullPointerException이 발생한다.
배열을 생성하고 배열 변수가 참조하는 상태에서 값을 저장하거나 읽어야 한다.
타입[ ] 변수 = null;
배열 객체를 생성하려면 값 목록을 이용하거나 new 연산자
를 이용하는 방법이 있다.
타입[] 변수 = {값0, 값1, 값2, 값3, ... };
중괄호 {}
는 주어진 값들을 항목으로 가지는 배열 객체를 힙에 생성하고, 배열 객체의 번지를 리턴한다.
배열 변수는 리턴된 번지를 저장함으로써 참조할 수 있다.
💡값의 목록으로 배열 객체를 생성할 때 주의할 점
배열 변수를 이미 선언한 후에는 다른 실행문에서 중괄호를 사용한 배열 생성이 허용되지 않는다.
new 연산자
를 사용해서 값 목록을 지정해 주어야 한다.타입[] 변수; 변수 = {값0, 값1, 값2, 값3, ... }; //NG, 컴파일 에러 변수 = new 타입[] {값0, 값1, 값2, 값3, ... }; //OK
값의 목록을 가지고 있지 않지만, 향후 값들을 저장할 배열을 미리 만들고 싶다면 new 연산자로 배열 객체를 생성할 수 있다.
타입[ ] 변수 = new 타입[길이];
길이는 배열이 저장할 수 있는 값의 개수를 말한다.
이미 배열 변수가 선언된 경우에도 new 연산자로 배열을 생성할 수 있다.
타입[ ] 변수 = null;
변수 = new 타입[길이];
new 연산자로 배열을 처음 생성할 경우 배열은 자동적으로 기본값으로 초기화된다.
분류 | 타입 | 초기값 |
---|---|---|
기본 타입(정수) | byte[ ] char[ ] short[ ] int[ ] long[ ] | 0 '\u0000' 0 0 0L |
기본 타입(실수) | float[ ] double[ ] | 0.0F 0.0 |
기본 타입(논리) | boolean[ ] | false |
참조 타입 | 클래스[ ] 인터페이스[ ] | null null |
배열이 생성되고 나서 특정 인덱스 위치에 새로운 값을 저장하려면 대입 연산자를 사용하면 된다.
int[] scores = new int[3];
scores[0] = 83;
scores[1] = 90;
scores[2] = 75;
배열의 길이란 배열에 저장할 수 있는 전체 항목의 개수를 말한다.
코드에서 배열의 길이를 얻으려면 배열 객체의 length
필드(객체 내부의 데이터)를 읽으면 되는데, length 필드는 읽기 전용 필드이기 때문에 값을 바꿀 수 없다.
int[] intArray = {10, 20, 30};
int num = intArray.length;
intArray.length = 10; //NG
배열의 인덱스 범위는 0 ~ (길이 - 1)
인데, 만약 인덱스를 초과해서 사용하면 ArrayIndexOutOfBoundsException이 발생한다.
다차원 배열이란 2차원 이상의 배열을 의미하며, 배열 요소로 또 다른 배열을 가지는 배열을 의미한다.
위에서 살펴본 배열과 달리 값들이 행과 열
로 구성된 배열을 2차원 배열이라고 하며, 2차원 배열은 가로 인덱스와 세로 인덱스를 사용한다.
자바는 2차원 배열을 중첩 배열 방식으로 구현한다. 예를 들어 2(행) x 3(열) 행렬을 만들기 위해서는 아래와 같은 코드를 사용한다.
int[][] myArray = new int[2][3];
예를 들어, 그룹화된 성적 점수를 이용해서 아래와 같은 2차원 배열을 만들 수 있다.
scores[0]에는 {95, 80} 배열을 참조하고, scores[1]에는 {92, 96} 배열을 참조한다.
int[][] scores = {{95, 80}, {92, 96}};
위 코드로 생성된 scores 배열에서 각 항몫 값은 아래와 같이 읽을 수 있다.
int score1 = scores[0][0]; //95
int score2 = scores[1][1]; //96
기본 타입 배열은 각 항목에 직접 값을 갖고 있지만, 참조 타입(클래스, 인터페이스) 배열은 각 항목에 객체의 번지를 가지고 있다.
예를 들어 String은 클래스이므로 String[] 배열은 각 항목에 문자열이 아니라, String 객체의 번지를 가지고 있다. String[] 배열은 String 객체를 참조하게 된다.
String[][] strArray = new String[3];
strArray[0] = "Java";
strArray[1] = "Kotlin";
strArray[2] = "Python";
따라서 String[] 배열의 항목도 결국 String 변수와 동일하게 취급되어야 한다.
예를 들어 String[] 배열 항목 간에 문자열을 비교하기 위해서는 ==
연산자 대신 equals()
메소드를 사용해야 한다.
String[] strArray = new String[3];
strArray[0] = "Java";
strArray[1] = "Java";
strArray[2] = new String("Java");
System.out.println(strArray[0] == strArray[1]); //true
System.out.println(strArray[0] == strArray[2]); //false
System.out.println(strArray[0].equals(strArray[2]); //true
배열은 한 번 생성하면 크기를 변경할 수 없기 때문에 더 많은 저장 공간이 필요하다면 더 큰 배열을 새로 만들고 이전 배열로부터 항목 값들을 복사해야한다.
배열 간의 항목 값들을 복사하려면 for문을 사용하거나 System.arraycopy() 메소드를 사용한다.
int[] oldIntArray = {1, 2, 3};
int[] newIntArray = new int[5];
for(int i = 0; i < oldIntArray.length; i++) {
newIntArray[i] = oldArray[i];
}
for(int i = 0; i < newIntArray.length; i++) {
System.out.print(newIntArray + " "); //1 2 3 0 0
}
String[] oldStrArray = {"java", "array", "copy"};
String[] newStrArray = new String[5];
System.arraycopy(oldStrArray, 0, newStrArray, 0, oldStrArray.length);
for (int i = 0; i < newStrArray.length; i++) {
System.out.print(newStrArray[i] + " "); //java array copy null null
}
int[][] myArray1 = {{1, 3},{5, 7}};
int[][] myArray2 = {{2, 4, 6}, {8, 10, 12}};
for (int i = 0; i < myArray1.length; i++) {
System.arraycopy(myArray1[i], 0, myArray2[i], 0, myArray1[i].length);
}
for(int i = 0; i < myArray2.length; i++) {
for(int j = 0; j < myArray2[i].length; j++) {
System.out.println("myArray2[" + i + "][" + j + "] = " + myArray2[i][j]);
}
}
//출력 결과
myArray2[0][0] = 1
myArray2[0][1] = 3
myArray2[0][2] = 6
myArray2[1][0] = 5
myArray2[1][1] = 7
myArray2[1][2] = 12