목차
- 배열 사용 이유
- 배열의 저장 구조(hashCode, length)
- 1차원 배열
3-1. 배열 선언
3-2. 배열 할당(배열 재할당, 배열의 회수)
3-3. 배열 초기화 - 다차원 배열
4-1. 2차원 배열 선언
4-2. 2차원 배열 할당(정변배열, 가변배열)
4-3. 2차원 배열 초기화 - 배열 예제
1. 배열 사용 이유
- 배열(array)은 같은 자료형의 변수들을 하나의 묶음으로 다루는 것이다.
- 배열은 저장된 값마다 index 번호가 부여된다. 즉, 연속된 메모리 공간에 값을 저장하고 이를 불러와 사용할 수 있는 것이다.
1-1. 연속된 메모리 공간으로 관리할 수 있다.
- 각각의 변수는 값을 1개씩만 담을 수 있다. 사용자(개발자)가 모든 변수의 이름을 알아야만 한다.
int var1 = 3;
int var2 = 7;
- 반면 배열은 여러 개의 값을 할당해놓고 사용할 수 있다.
int var[] = {3, 7};
arr[0] = 3;
arr[1] = 7;
1-2. 반복문을 통한 연속 처리가 가능하다.
- 배열을 사용하면 반복문을 통한 값 대입이 가능하다.
- 반복문 초기식이 반드시 하나여야 하는 것은 아니다.
for(int i=0, value=0; i < arr.length; i++) {
arr[i] = value += 10;
}
- 배열을 사용하면 반복문을 통한 연속 처리가 가능하다.
int sum = 0;
for(int i=0; i < arr.length; i++) {
sum += arr[i];
}
System.out.println("sum : " + sum);
✅ 배열의 사용 목적을 이해할 수 있다.
2. 배열의 저장 구조
- stack, heap, static 영역별로 나뉘어 각각의 주소값을 참조하고 있다.
- heap 영역은 값이 없어서는 안 된다. 따라서 처음 배열 선언 시 자료형별 기본값으로 초기화된다.
정수형 기본값 int = 0
실수형 기본값 double = 0.0
논리형 기본값 boolean = false
문자형 기본값 char = \u0000(공백문자)
참조형 문자열 기본값 String = null
int[] arr = new int[3]을 시각화하면 다음과 같다.
stack | heap | static |
arr (주소값 0x123) |
arr[0]-arr[1]-arr[2] (주소값 0x123) |
- 선언 및 할당을 마친 배열을 출력문 통해 System.out.println(arr); 불러오면 16진수로 표현된 주소값이 출력된다.
iarr : [I@7637f22
carr : [C@3830f1c0
hashCode() 메소드
- 10진수로 변환된 주소값을 출력한다.
- 일반적으로 객체의 주소값을 10진수로 변환하여 생성한 객체의 고유한 정수값을 반환한다.
- 동일객체인지 비교할 때 사용할 목적으로 쓰인다.
- 동등객체(가지고 있는 값이 같은 객체)를 동일객체 취급하기 위한 용도로 overriding해서 사용한다.
iarr의 hashcode : 123961122
carr의 hashcode : 942731712
배열의 길이 arr.length
❗ 배열의 길이는 필드이기 때문에 length;
❗ String의 문자열 길이는 메소드로 제공하고 있기 때문에 length();로 사용한다.
2-1. 배열 재할당
- 한 번 지정한 배열의 크기는 변경하지 못한다.
- 새로운 배열을 생성하여 그 주소값을 레퍼런스 변수에 덮어써야 한다.
- 각각의 hashCode를 살펴보면 다른 값을 가지고 있는 것을 확인할 수 있다.
2-2. 배열의 회수
- 한 번 할당된 배열은 지울 수 없다.
- 다만 레퍼런스 변수 값을 null;로 변경하면, 더 이상 주소가 참조되지 않는 배열은 일정 시간이 지난 후 heap의 old 영역으로 이동하여 GC(garbage collector, 가비지컬렉터)가 삭제시킨다.
- 즉 사용자(개발자)가 회수 과정을 관리할 필요가 없다. 이는 자바 언어의 큰 특징이다.
darr = null;
- null; 값으로 비워둔 변수의 lengh나 hashCode()를 물을 경우 java.lang.NullPointerException 오류가 발생한다.
- 참조 변수가 null;이라는 값을 가지는 것은 어떤 주소도 참조하지 않는다, 비워져있다는 뜻이다.
- 이처럼 한 번 주소 값을 잃어버린 배열은 다시 참조 불가능하다.
✅ 배열의 저장 구조를 이해할 수 있다.
✅ 배열 선언 시 기본 자료형별 기본값으로 초기화됨을 이해할 수 있다.
✅ 선언 및 할당된 배열의 주소값과 길이를 확인해 비교할 수 있다.
✅ 배열의 재할당 과정을 이해할 수 있다.
✅ 배열의 회수 과정을 이해할 수 있다.
3. 1차원 배열
3-1. 배열 선언(stack 영역)
- 배열 선언이란 stack 영역에 배열의 주소를 보관할 수 있는 공간을 만드는 것이다.
❗ 자료형[] 배열명; int[] arr;
❗ 자료형 배열명[]; int arr[];
- 문법적으로는 위 방법 둘 다 사용 가능하다.
- 하지만 일반 자료형이 아니라 배열의 자료형이라는 것을 직관적으로 명시하기 위해 자료형 뒤에 대괄호[] 붙이는 것이 나을 수 있다.
3-2. 배열 할당(heap 영역)
- 배열은 참조변수(reference type)이다. Heap 영역에 할당된 배열 공간의 주소를 참조하여 사용하기 때문이다.
- 배열 공간의 주소를 이용해 index를 참조하는 방식으로 값을 처리한다.
❗ 배열명 = new 자료형[배열크기]; arr = new int [10];
- new 연산자는 heap 영역에 공간을 만들고, 여기에 생겨난 주소값을 반환하는 연산자이다.
- 배열을 할당할 시에는 배열의 크기를 반드시 지정해 주어야 한다. 크기를 지정하지 않으면 Variable must provide either dimension expressions or an array initializer 오류 메시지가 나타난다.
- 배열도 선언과 할당을 동시에 할 수 있다.
❗ int[] arr = new int[4];
3-3. 배열 초기화
index를 이용한 초기화
arr[0] = 1;
arr[1] = 2;
for문을 이용한 초기화
- 초기화할 리터럴 값이 규칙적이라면 반복문을 통한 배열 초기화가 가능하다.
for(int i=0; i < arr.length; i++) {
arr[i] = i;
}
선언과 동시에 초기화
- 초기화할 값들이 결정된 상황이라면 블럭 {}으로 나열할 수 있다.
- new 자료형[]는 생략할 수 있으며, 블럭 {}에 작성한 값의 개수만큼 자동으로 크기가 설정된다.
- 같은 자료형으로 이루어진 배열의 그 특성상 초기화할 값 역시 동일한 자료형으로 이루어져 있어야 한다.
- 만일 숫자도 문자열도 포함한 값을 설정해야 한다면 다음과 같이 String으로 적용해야 한다: {"1", "2", "3", "넷", "다섯"}
int[] arr = {1, 2, 3, 4, 5};
int[] arr =new int[]{1, 2, 3, 4, 5}
String fruit[] = {"사과", "포도", "참외"};
✅ 배열을 선언하고 할당할 수 있다.
✅ 배열에서 각 인덱스가 가진 의미를 이해할 수 있다.
✅ 배열의 인덱스별로 값을 대입하고 사용할 수 있다.
✅ 배열 초기화 과정에서 연속 처리가 필요한 경우 반복문을 활용할 수 있다.
4. 다차원 배열
- 다차원 배열은 2차원 이상의 배열을 말한다. 필요하다면 3차원, 4차원 등등 표현할 순 있으나 주된 사용 빈도는 2차원 정도에 그친다.
- 2차원 배열은 1차원 배열들의 묶음이다.
- 예를 들어 new int[3][4]를 할당하면 아래와 같이 index가 부여된다.
[0][0] | [0][1] | [0][2] | [0][3] |
[1][0] | [1][1] | [1][0] | [1][3] |
[2][0] | [2][1] | [2][2] | [2][3] |
4-1. 2차원 배열 선언(stack 영역)
- 아래 세 가지 모두 문법적으로 사용 가능하다.
- 배열 선언이란 1차원 배열에서와 마찬가지로 stack 영역에 참조변수를 만드는 과정이다.
❗ 자료형[][] 배열명;
❗ 자료형 배열명[][];
❗ 자료형[] 배열명[];
4-2. 2차원 배열 할당(heap 영역)
- heap 영역에 실제 주소값을 가진 공간을 만드는 과정이다.
❗ 자료형[][] 배열명 = new 자료형[행크기][열크기];
행크기 → 할당할 배열의 갯수
열크기 → 할당할 배열의 길이
정변배열
- 관리하는 여러 개의 배열 길이가 동일한 경우 아래와 같이 선언과 동시에 할당할 수가 있다.
- 길이가 5로 동일한 1차원 배열을 3개 할당하고, 그 주소들을 묶어 관리하는 배열의 주소들을 stack 영역의 arr에 저장했음을 나타낸다.
int[][] arr = new int[3][5];
가변배열
- 가변배열이라 함은 1차원 배열의 길이가 각각 다름을 말한다. 따라서 선언과 동시에 일괄 할당은 불가하다.
- 행의 길이를 먼저 할당하고, 각 열마다 뒤따라야 하는 길이를 별도 설정한다.
int[][] arr = new int[3][];
arr[0] = new int[3];
arr[1] = new int[4];
- 이때 미리 할당해둔 배열을 활용할 수도 있다.
- 원래 존재하고 있던 arrFive(주소값 0x987)를 arr[2]가 똑같이 참조하게 되었음(주소값 0x987)을 의미한다.
int arrFive = new int[5];
arr[2] = arrFive;
- 배열을 다룰 때 주의할 점은 인덱스 값의 사용 시에 있다.
- 존재하지 않는 배열과 인덱스(행, 열)에 접근하면 범위를 벗어났다는 에러 메시지 java.lang.ArrayIndexOutOfBoundsException가 나타나고, 할당되지 않은 배열(행)을 입력하면 NullPointerException 오류가 발생한다.
4-3. 2차원 배열 초기화
index를 이용한 초기화
arr[0][0] = 1;
arr[1][1] = 2;
for문을 이용한 초기화
- 반복문을 중첩하여 활용한다.
- 정변배열이든 가변배열이든 중첩 for문의 조건식은 달라지지 않는다.
- 행은 외부 for문에 작성한다. 행의 길이를 i < arr.length;로 확인할 수 있다.
- 열은 내부 for문에 작성한다. 열의 길이는 i < arr[i].length;로 확인할 수 있다.
for(int i=0; i < arr.length; i++) {
for(int j=0; j < arr[i].length; j++) {
arr[i][j] = j;
}
}
선언·할당과 동시에 초기화
- 블럭이 중첩돼 사용된다.
- new 자료형 생략 가능하다.
int[][] arr = {{1, 2, 3, 4}, {5, 6, 7, 8}};
int[][] arr =new int{{1, 2, 3, 4}, {5, 6, 7, 8}};
- 아래는 각각 정변배열, 가변배열에 해당되는 예시이다. 선언·할당과 동시에 블럭 안에 각 배열의 값들을 나열해 초기화까지 진행된 모습이다.
int[][] iarr = {{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {11, 12, 13, 14, 15}};
int[][] iarr2 = {{1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11, 12}};
- 다차원 배열의 경우에도 미리 할당된 배열을 참조할 수가 있다.
int[] arrOne = {1, 2, 3, 4, 5};
int[] arrTwo = {6, 7, 8, 9, 10};
int[][] arr = {arrOne, arrTwo};
✅ 다차원 배열의 저장 구조를 이해할 수 있다.
✅ 다차원 배열을 선언하고 할당할 수 있다.
✅ 다차원 배열에서 각 인덱스가 가진 의미를 이해할 수 있다.
✅ 다차원 배열의 인덱스별로 값을 대입하고 사용할 수 있다.
✅ 다차원 배열 연속 처리 시 반복문을 활용할 수 있다.
5. 배열 예제
A. 입력 받은 5명의 점수를 토대로 합계 및 평균 점수 구하기
package com.reminder.array;
import java.util.Scanner;
public class Array01 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[] scores = new int[5];
for(int i=0; i < scores.length; i++) {
System.out.print((i + 1) +"번째 학생의 점수를 입력하세요 : ");
scores[i] = scanner.nextInt();
}
double sum = 0.0;
double avg = 0.0;
for(int i=0; i < scores.length; i++) {
sum += scores[i];
}
avg = sum / scores.length;
System.out.println("합계 : " + sum);
System.out.println("평균 : " + avg);
}
}
B. 랜덤 카드 게임
package com.reminder.array;
public class Array02 {
public static void main(String[] args) {
String[] shapes = {"SPADE", "CLOVER", "HEART", "DIAMOND"};
String[] numbers = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "JACK", "QUEEN", "KING", "ACE"};
int randomShapesIndex = (int)(Math.random() * shapes.length);
int randomNumbersIndex = (int)(Math.random() * numbers.length);
System.out.println("당신이 뽑은 카드는 " + shapes[randomShapesIndex] + " " + numbers[randomNumbersIndex] + "입니다.");
}
}
'Java' 카테고리의 다른 글
[JAVA] 5-2. 배열의 복사 및 정렬 (0) | 2021.12.28 |
---|---|
[JAVA/수업 과제 practice] 배열 | 다차원 배열 Lv. 1~2 (0) | 2021.12.27 |
[자바의 정석] Ch 4. 제어문 예제 응용 학습 (0) | 2021.12.26 |
[JAVA/수업 과제] 반복문, 분기문 practice (0) | 2021.12.26 |
[자바의 정석] Ch 4. 제어문 연습문제 풀이 (0) | 2021.12.25 |