같은 타입의 여러 변수를 하나의 묶음으로 다루는 것
int[] score = new int[3];
변수 score는 배열을 다루는 데 필요한 참조변수일 뿐 값을 저장하기 위한 공간은 아님
변수와 달리 배열은 각 저장공간이 연속적으로 배치되어 있다.
// 배열 선언(배열을 다룰 참조변수 선언)
타입[] 변수이름;
타입 변수이름[];
// 배열 생성(실제 저장 공간을 생성)
변수이름 = new 타입[길이]
생략
배열 길이의 최대값은 int 타입의 최대값, 약 20억
길이가 0인 배열도 생성 가능
JVM이 모든 배열의 길이를 별도로 관리 → 배열이름.length를 통해 길이 정보
배열은 한 번 생성하면 길이를 변경할 수 없으니까 배열이름.length는 상수
더 큰 배열을 새로 생성
기존 배열의 내용을 새로운 배열에 복사
비용이 많이 드는 방법이므로 새 배열을 생성해야 하는 상황이 가능한 적게 발생하도록
너무 크게 잡으면 메모리 낭비니까 기존의 2배 정도의 길이로
생성과 동시에 자동적으로 자신의 타입에 해당하는 기본값으로 초기화
for문 사용 → 저장하려는 값에 일정한 규칙이 있어야지 사용 가능
int[] score = new int[] {50, 60, 70, 80, 90};
int[] score = {50, 60, 70, 80, 90};
다만 배열의 선언과 생성을 따로 하는 경우엔 생략할 수 없음
int[] score;
score = new int[] {50, 60, 70, 80, 90};
// score = {50, 60, 70, 80, 90}; // 에러
매개변수로 배열을 받는 메서드를 호출할 경우 ‘new 타입[]’ 생략 불가능
int add(int[] arr){ /* 내용 생략 */ }
int result = add(new int[] {100, 90, 80, 70, 60});
int result = add({100, 90, 80, 70, 60}); // 에러
괄호 안에 아무것도 넣지 않으면 길이가 0인 배열
배열의 값을 바로 출력하면 타입@주소가 출력되는데, 이때의 주소는 실제 주소가 아닌 내부 주소. 실행할 때마다 달라질 수 있다.
예외적으로 char 배열은 println 메서드로 출력하면 각 요소가 구분자 없이 그대로 출력됨
char[] chArr = {'a', 'b', 'c', 'd'};
System.out.println(chArr); // abcd
int[] arr = new int[5];
int[] tmp = new int[arr.length * 2];
for(int i = 0; i < arr.length; i++){
tmp[i] = arr[i];
}
arr = tmp; // 참조변수 arr이 새로운 배열을 가리키게 한다.
참조변수 arr과 tmp는 같은 배열을 가리키게 된다. 즉, 배열 arr과 배열 tmp는 이름만 같을 뿐 동일한 배열이다. 그리고 전에 arr이 가리키던 배열은 더이상 사용할 수 없게 된다.
→ 배열은 참조변수를 통해서만 접근할 수 있기 때문에 자신을 가리키는 참조변수가 없는 배열은 JVM의 가비지 컬렉터에 의해서 자동적으로 메모리에서 제거된다.
for문은 배열의 요소 하나하나에 접근해서 복사하지만 arraycopy()는 지정된 범위의 값을 한 번에 통째로 복사한다. 각 요소들이 연속적으로 저장되어 있는 배열의 특성 때문에 이러한 처리가 가능하다.
System.arraycopy(num, 0, newNum, 0, num.length);
// num[0]에서 newNum[0]으로 num.length 개의 데이터를 복사
생략
public class ArrayMaxMin {
public static void main(String[] args) {
int[] score = {79, 88, 91, 33, 100, 55, 95};
int max = score[0];
int min = score[0]; // 배열의 첫번째 값으로 최소값을 초기화
for(int i = 1; i < score.length; i++){
if(score[i] > max){
max = score[i];
} else if (score[i] < min){
min = score[i];
}
} // end of for
System.out.println("최대값: " + max);
System.out.println("최소값: " + min);
}
}
public class ArrayShuffle {
public static void main(String[] args) {
int[] numArr = new int[10];
for (int i = 0; i < numArr.length; i++){
numArr[i] = i; // 배열을 0~9까지의 숫자로 초기화한다.
System.out.println(numArr[i]);
}
System.out.println();
for(int i = 0; i < numArr.length; i++){
int n = (int)(Math.random() * numArr.length); // random한 인덱스를 만듦
int tmp = numArr[0];
numArr[0] = numArr[n];
numArr[n] = tmp;
}
for(int i = 0; i < numArr.length; i++){
System.out.println(numArr[i]);
}
} // end of main
}
cf) 값을 넣는 게 아니라 인덱스로 위치만 바꾸는 것이므로 중복된 값은 생기지 않는다.
카드놀이 하려고 카드를 섞을 때 새로운 카드가 갑자기 생기지 않듯이
public class Lotto {
public static void main(String[] args) {
// 로또 번호 생성
int[] ball = new int[45];
// 배열의 각 요소에 1 ~ 45의 값을 저장한다.
for(int i = 0; i < ball.length; i++){
ball[i] = i + 1;
}
int tmp = 0; // 두 값을 바꾸는 데 사용할 임시 변수
int j = 0; // 임의의 값을 얻어서 저장할 변수
// 배열의 i번째 요소와 임의의 요소에 저장된 값을 서로 바꿔서 값을 섞는다.
// 0 ~ 5까지 6개의 요소만 바꾼다
for(int i = 0; i < 6; i++){
j = (int)(Math.random() * ball.length);
tmp = ball[i];
ball[i] = ball[j];
ball[j] = tmp;
}
// 6개 뽑기
for(int i = 0; i < 6; i++){
System.out.printf("ball[%d] = %d%n", i, ball[i]);
}
} // end of main
}
import java.util.Arrays;
public class ArrayCountingNumbers {
public static void main(String[] args) {
// 길이가 10인 배열을 만들고 0 ~ 9 사이의 임의의 값으로 초기화
// 저장된 각 숫자가 몇 번 반복해서 나타나는지를 배열 counter에 담은 다음 출력
int[] numbers = new int[10];
int[] counter = new int[10];
for(int i = 0; i < numbers.length; i++){
numbers[i] = (int)(Math.random() * 10); // 0 <= x < 10
}
for(int i = 0; i < numbers.length; i++){
counter[numbers[i]]++;
}
System.out.println(Arrays.toString(numbers));
System.out.println(Arrays.toString(counter));
}
}
String 클래스는 char 배열에 기능(메서드)을 추가한 것
char 배열과 String 클래스의 중요한 차이: String 객체는 읽을 수만 있을 뿐 내용을 변경할 수 없다.
String str = "Java";
str = str + "8";
System.out.println(str); // Java8
문자열 str의 내용이 변경되는 것 같지만, 문자열은 변경할 수 없으므로 새로운 내용의 문자열이 생성된다. (변경 가능한 문자열을 위해선 StringBuffer를 사용해야 한다)
char charAt(int index) 해당 인덱스의 문자를 반환
int length() // 문자열의 길이를 반환
String substring(int from, int to) // 해당 범위의 문자열을 반환, to는 포함되지 않음
boolean equals(Object obj) // 내용 비교
char[] toCharArray() // 문자열을 문자 배열로 변환해서 반환
char[] chArr = {'A', 'B', 'C'};
String str = new String(chArr); // char -> string
char[] tmp = str.toCharArray(); // string -> char
생략
향상된 for문을 사용해 2차원 배열 score의 모든 요소의 합을 구하기
for(int[] tmp : score) {
for(int i : tmp) {
sum += i;
}
}
⇒ 향상된 for문으로 배열의 각 요소에 저장된 값들을 순차적으로 읽어올 수는 있지만, 배열에 저장된 값을 변경할 수는 없다.
다차원 배열을 생성할 때 전체 배열 차수 중 마지막 차수의 길이를 지정하지 않고, 추후에 각기 다른 길이의 배열을 생성함으로써 유동적인 가변 배열 구성 가능
int[][] scores = new int[5][];
scores[0] = new int[4];
scores[1] = new int[3];
scores[2] = new int[2];
scores[3] = new int[2];
scores[4] = new int[3];
물론 중괄호를 이용하여 생성과 초기화 동시에 하는 것도 가능.
빙고
import java.util.Scanner;
public class Bingo {
public static void main(String[] args) {
final int SIZE = 5;
int x = 0, y = 0, num = 0;
int[][] bingo = new int[SIZE][SIZE];
Scanner sc = new Scanner(System.in);
// 배열의 모든 요소를 1부터 SIZE*SIZE까지의 숫자로 초기화
for(int i = 0; i < SIZE; i++){
for(int j = 0; j < SIZE; j++){
bingo[i][j] = i*SIZE + j + 1;
// [0][1] = 1
// [1][0] = 6
// [2][0] = 11
// 12345
// 678910
// 이런식으로 저장됨
}
}
// 배열에 저장된 값을 뒤섞는다.
for(int i = 0; i < SIZE; i++){
for(int j = 0; j < SIZE; j++){
x = (int)(Math.random() * SIZE);
y = (int)(Math.random() * SIZE);
int tmp = bingo[i][j];
bingo[i][j] = bingo[x][y];
bingo[x][y] = tmp;
}
}
do{
for(int i = 0; i < SIZE; i++){
for(int j = 0; j < SIZE; j++){
System.out.printf("%2d ", bingo[i][j]);
}
System.out.println();
}
System.out.println();
System.out.printf("1 ~ %d의 숫자를 입력하세요. (종료 0)", SIZE*SIZE);
num = sc.nextInt();
outer:
for(int i = 0; i < SIZE; i++){
for(int j = 0; j < SIZE; j++){
if(bingo[i][j] == num){
bingo[i][j] = 0;
break outer;
}
}
}
} while(num != 0);
} // end for main
}