1. 배열(Array)
1.1 배열이란?
Def) 배열: 같은 타입의 여러 변수를 하나의 묶음으로 다루는 것을 배열이라고 한다.
1.2 배열의 선언과 생성
- 선언 방법
-> 타입[] 변수이름 ex) int[] score; String[] name
-> 타입 변수이름[] ex) int score[]; String name[]
- 배열의 생성
-> 변수이름 = new 타입[길이] // 배열을 생성(실제 저장공간을 생성한다.)
- 배열의 선언과 생성을 동시에 할 수 있다.
<hide/>
int score = new int[5];
1.3 배열의 길이와 인덱스
- 인덱스의 범위는 0부터 '배열 길이 -1'까지
- 인덱스 0부터 시작한다.
- 배열의 범위에 속하지 않는 값을 인덱스로 하여 출력하도록 하면 "ArrayIndexOutOfBoundsException" 발생한다.
-> ArrayIndexOutOfBoundsException : 배열의 index가 유효한 범위을 벗어났다는 에러가 난다.
- 배열 길이는 거의 제약이 없다.
- 배열 길이는 JVM이 관리한다.
- 배열의 길이 변경하기 (변경할 수 없고 새로 만들어야한다. )
(1) 더 큰 배열을 새로 생성한다.
(2) 기존 배열의 내용을 새로운 배열에 복사한다.
1.4 배열의 초기화
- 배열의 길이가 큰 경우에는 요소 하나하나에 값을 지정하기 보다는 for문을 사용하면 좋다.
- 배열의 생성과 초기화를 한 번에 할 수 있다.
<hide/>
int score = new int[]{ 50, 60, 70, 80, 90 };
int score = { 50, 60, 70, 80, 90 }; // new int 생략 가능하다.
- 배열의 선언과 생성을 따로하는 경우는 new int를 생략할 수 없다.
<hide/>
int[] score;
score = new int[]{ 50, 60, 70, 80, 90 }; // 정상
score = { 50, 60, 70, 80, 90 }; 에러.new int[] 생략할 수 없다.
- Arrays.ToString(배열 이름) : 배열의 모든 요소를 '[ 첫번째 요소, 두번째 요소, ...]'와 같은 형식의 문자열로
- 만들어서 반환한다. (모든 요소를 출력한다. )
Ex ) int[] iArr이라는 배열이 있을 때, iArr의 값을 하나씩 출력하거나 또는 Arrays.ToString 메서드를 이용하지 않고
바로 출력하면 오류가 난다.
-> iArr은 참조변수이기 때문에 변수에 저장된 값, 즉 배열의 주소가 출력될 것이기 때문이다.
-> "타입@주소"형식으로 출력된다.
-> 배열을 가리키는 참조변수를 출력해봐야 별로 얻을 정보가 없다.
-> 예외적으로 char배열은 println메서드로 출력하면 각 요소가 구분자 없이 그대로 출력된다.
-> println()메서드가 char배열일 때만 이렇게 동작하도록 작성되었기 때문이다.
1.5 배열의 복사
1) 얕은 복사: 값의 주소를 저장한다.
2) 깊은 복사: 배열의 원소를 하나하나 저장한다.
Ex) ArrayEx2 - 얕은 복사
<hide/>
int[] arr= {1, 2, 3, 4, 5};
int[] tmp = new int[arr.length * 2];
for(int i = 0;i < arr.length;++i){
tmp[i] = arr[i];
}
arr = tmp;
System.out.println(Arrays.toString(arr));
System.out.println(Arrays.toString(tmp));
- 참조변수 arr에 참조변수 tmp의 값을 저장한다.
- arr = tmp 와 같이 대입하고 난 다음에는, 이름만 다를 뿐 완전히 같은 배열이 된다.
- 즉, arr 과 tmp의 주솟값이 같기 때문에 arr == tmp 를 조회하면 true이다.
- 배열은 참조변수를 통해서만 접근가능하므로 자신을 가리키는 참조변수가 없는 배열은 사용할 수 없다. 이렇게 쓸모없게 된 배열은 JVM의 가비지 컬렉터에 의해 자동 제거된다.
Note) 실행 결과
Ex) 얕은 복사, 깊은 복사
<hide/>
public class ArrayTest {
public static void main(String[] args) {
int [] arr1 = {10, 20, 25, 30, 45};
//얕은 복사
int[] arr2 = new int[arr1.length];
arr2 = arr1;
for(int i= 0; i < arr1.length; ++i) {
System.out.println(arr1[i]);
}
for(int i= 0; i < arr2.length; ++i) {
System.out.println(arr2[i]);
}
//깊은 복사
int[] arr3 = new int[arr1.length];
for(int i = 0;i < arr3.length; ++i) {
arr3[i] = arr1[i];
}
for(int i= 0; i < arr3.length; ++i) {
System.out.println(arr3[i]);
}
}
}
Note) 실행 결과
Ex) 배열의 복사
- int [] c1 = {1, 2, 3, 4};
1) int [] c2 = Arrays.copyOf(c1, c1.length);
2) int [] c2 = c1.clone(); // Object.clone();
3) System.arraycopy() : System클래스의 arraycopy()를 사용하면 배열을 복사할 수 있다.
- System.arraycopy( num, 0, newNum, 0, num.length ) : num[0]에서 newNum[0]으로 num.length개의 데이터를 복사한다.
<hide/>
package javaStudy;
public class ArrayEx4 {
public static void main(String[] args) {
char[] abc = { 'A', 'B', 'C', 'D'};
char[] num = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
System.out.println(abc);
System.out.println(num);
char[] result = new char[ abc.length + num.length ];// abc와 num을 붙여서 하나의 배열로 만든다.
System.arraycopy(abc, 0, result, 0, abc.length);
System.arraycopy(num, 0, result, abc.length, num.length);
System.out.println(result);
System.arraycopy(abc, 0, num, 0, abc.length); // 배열abc를 배열num의 첫번째 위치부터 배열abc길이만큼 복사한다.
System.out.println(num);
System.arraycopy(abc, 0, num, 6, 3); // num의 index 6번 위치에 3개를 복사한다.
System.out.println(num);
}
}
Note) 실행 결과
1.6 배열의 활용
Ex 5-8) 로또 번호 만들기
<hide/>
package javaStudy;
public class ArrayEx8 {
public static void main(String[] args) {
int[] ball = new int[45];
for(int i = 0; i < ball.length; ++i)
ball[i] = i + 1; // ball[0]에 1이 저장된다.
int temp = 0; // 두 값을 바꾸기 위한 임시 변수
int j = 0; // 임의의 값을 얻어서 저장할 변수
for(int i = 0; i < 6; ++i) {
j = (int)(Math.random() * 45); // 0~44사이의 임의의 값을 얻는다.
temp = ball[i];
ball[i] = ball[j];
ball[j] = temp;
}
for(int i = 0; i < 6; ++i)
System.out.printf("ball[%d] = %d%n", i, ball[i]);
}
}
Note) 실행 결과
- 먼저, 길이가 45인 배열에 1부터 45까지의 값을 담는다.
- 반복문을 이용해서 ball[i]와 random()에 의해서 결정된 임의의 위치에 있는 값과 자리를 바꾸는 것을 6번 반복한다.
- 1 ~ 45번까지 번호가 쓰인 카드를 섞어서 맨 위의 6장을 꺼내는 것과 같다.
Ex 5-10) 버블소트(Bubble Sort)
<hide/>
package javaStudy;
public class ArrayEx10 {
public static void main(String[] args) {
int[] numArr = new int[10];
for(int i = 0; i < numArr.length; ++i) {
System.out.print(numArr[i] = (int)(Math.random() * 10 ));
}
System.out.println();
for(int i = 0; i < numArr.length - 1 ; ++i) {
boolean changed = false; // 자리바꿈이 생겼는지 확인한다.
for(int j = 0; j < numArr.length - 1 - i; ++j) {
if(numArr[j] > numArr[j + 1] ) { // 오른쪽 값이 작으면 서로 바꾼다.
int temp = numArr[j];
numArr[j] = numArr[j + 1];
numArr[j + 1] = temp;
changed = true; // 자리바꿈이 발생했으니 changed를 true로 바꾼다.
}
}
if( !changed) break; // 자리바꿈이 없으면 반복문을 벗어난다.
for(int k = 0; k < numArr.length; ++k)
System.out.print(numArr[k]); // 정렬된 결과를 출력한다.
System.out.println();
}
}
}
Note) 실행 결과
- 길이가 10인 배열에 0 ~ 9사이의 임의 값으로 채운 다음에 버블 소트 알고리즘을 통해서 크기순으로 배열한다.
- 배열의 길이가 n일 때, 배열의 첫 번째부터 n - 1까지의 요소에 대해 근접한 값과 크기를 비교해서 자리 바꿈을 반복.
- for문을 비교할수록 비교해야 하는 범위는 하나씩 줄어든다.
- 그래서 원래는 numArr.length - 1 번을 비교해야 하는데
- 매 반복마다 비교횟수가 1씩 줄어들므로 바깥쪽 for문의 제어 변수 i를 빼주는 것이다.
- 자리 바꿈이 없다는 건 정렬이 완료됨을 뜻한다. 자리바꿈 없으면 break로 반복문으로 빠져나간다.
2. String 배열
2.1 String배열의 선언과 생성
String[] name = new String[3]; // 3개의 문자열을 담을 수 있는 배열을 생성한다.
- 3개의 String타입의 참조변수를 저장하기 위한 공간이 마련되도 참조형 변수의 기본 값은 null이므로 각 요소의 값은 null로 초기화 된다.
- String은 클래스이므로 new 연산자를 이용해서 객체를 생성해야만 한다.
2.2 String 배열의 초기화
Ex 5-13) 16진수를 2진수로 변환
<hide/>
package javaStudy;
public class ArrayEx13 {
public static void main(String[] args) {
char[] hex = {'C', 'A', 'F', 'E'};
String[] binary = { "0000", "0001", "0100", "0011",
"0100", "0101", "0110", "0111",
"1000", "1001", "1010", "1011",
"1100", "1101", "1110", "1111"};
String result = "";
for(int i = 0; i < hex.length; ++i) {
if( '0' <= hex[i] && hex[i] <= '9') {
result += binary[hex[i] - '0']; // '8'-'0'의 결과는 8이다.
}else {
result += binary[hex[i] - 'A' + 10 ]; // 'C' - 'A'의 결과는 2이다.
}
} //String(char[] value)
System.out.println("hex: "+ new String(hex));
System.out.println("binary: "+ result );
}
}
Note) 실행 결과
- 변환하고자 하는 16진수를 hex에 나열한다.
- 문자 배열 binary에는 0000~1111까지 모두 16개의 값을 문자열로 저장한다.
- for문을 이용하여 배열 hex에 저장된 문자를 하나씩 읽어서 그에 해당하는 이진수 표현을
- 배열 binary에서 얻어 result에 덧붙이고 그 결과를 화면에 출력한다.
2.3 char배열과 String 클래스
- 자바에서는 char 배열이 아닌 String클래스를 이용해서 문자열을 처리한다.
- 그 이유는 String클래스가 char배열에 여러 가지 기능(메서드)을 추가하여 확장한 것이기 때문이다.
- 그러므로 char보다 String을 사용하는 게 문자열을 다루기 더 편하다.
- String클래스의 주요 메서드
-> 문자열이름.charAt(int index) : 문자열에서 해당 위치(index)에 있는 문자를 반환한다.
-> int length() : 문자열의 길이를 반환한다.
-> 문자열이름.substring(int from, int to) : 문자열에서 해당 범위(from~to)에 있는 문자열을 반환한다. (to는 포함 X)
-> char[] toCharArray() : 문자열을 문자 배열(char[])로 변환해서 반환한다.
- String과 char의 변환
Ex 5-14)
<hide/>
package javaStudy;
public class ArrayEx14 {
public static void main(String[] args) {
String src = "ABCDE";
for(int i = 0; i < src.length(); ++i ) {
char ch = src.charAt(i); // src의 i번째 문자를 ch에 저장한다.
System.out.println("src.charAt(" + i+ "):"+ ch);
}
char[] chArr = src.toCharArray(); // String을 char[]로 변환
System.out.println(chArr); // char배열(char[])을 출력
}
}
Note) 실행 결과
- char[] chArr = src.toCharArray(); String src를 char[]로 변환
2.4 커맨드 라인을 통해 입력받기
- 커맨드 라인을 이용해서 프로그램을 실행할 때 클래스 이름 뒤에 공백 무자로 구분하여
- 여러 개의 문자열을 프로그램에 전달할 수 있다.
- Integer.parseInt(): 문자열을 숫자로 바꾸는 메서드
3. 다차원 배열
3.1 2차원 배열의 선언과 인덱스
- 2차원 배열을 선언하는 방법은 1차원 배열과 같다. 괄호[]가 하나 더 들어간다.
- 아래 코드는 4행 3열의 2차원 배열을 생성.
int [][] score = new int[4][3];
3.2 2차원 배열의 초기화
Ex 5-18)
<hide/>
package javaStudy;
public class ArrayEx18 {
public static void main(String[] args) {
int [][] score = {
{100, 100, 100},
{20, 20, 20},
{30, 30, 30},
{40, 40, 40}
};
int sum = 0;
for(int i = 0; i < score.length; ++i) {
for(int j = 0; j < score[i].length; ++j) {
System.out.printf("score[%d][%d] = %d%n", i, j, score[i][j]);
}
}
for(int[] tmp : score) { // score의 각 요소(1차원 배열 주소)를 tmp에 저장
for(int i : tmp) { // tmp는 1차원 배열을 가리키는 참조 변수
sum += i;
}
}
System.out.println("sum = " + sum);
}
}
Note) 실행 결과
- 2차원 배열score의 모든 요소의 합을 구하고 출력하는 예제이다.
3.3 가변 배열
- 2차원 이상의 다차원 배열을 생성할 때. 전체 배열 차수 중 마지막 차수의 길이를 지정하지 않고
- 추후에 각기 다른 길이의 배열을 생성함으로써 고정된 형태가 아닌 보다 유동적인 가변 배열을 구성할 수 있다.
3.4 다차원 배열의 활용
Ex 5-20) 입력한 2차원 좌표의 위치에 X를 표시
<hide/>
package javaStudy;
import java.util.*;
public class MutiArrEx1 {
public static void main(String[] args) {
final int SIZE = 10;
int x = 0, y = 0;
char [][] board = new char[SIZE][SIZE];
byte [][] shipBoard = {
// 1 2 3 4 5 6 7 8 9
{ 0, 0, 0, 0, 0, 0, 1, 0, 0 }, // 1
{ 1, 1, 1, 1, 0, 0, 1, 0, 0 }, // 2
{ 0, 0, 0, 0, 0, 0, 1, 0, 0 }, // 3
{ 0, 0, 0, 0, 0, 0, 1, 0, 0 }, // 4
{ 0, 0, 0, 0, 0, 0, 1, 0, 0 }, // 5
{ 1, 1, 0, 1, 0, 0, 0, 0, 0 }, // 6
{ 0, 0, 0, 1, 0, 0, 0, 0, 0 }, // 7
{ 0, 0, 0, 1, 0, 0, 0, 0, 0 }, // 8
{ 0, 0, 0, 0, 0, 1, 1, 1, 0 } // 9
};
for(int i = 1; i < SIZE; ++i)
board[0][i] = board[i][0] = (char)(i + '0');
Scanner scanner = new Scanner(System.in);
while(true) {
System.out.printf("좌료를 입력하세요.(종료는 00)>");
String input = scanner.nextLine(); // 화면에 입력받은 내용을 input에 저장
if(input.length() == 2) { // 두 글자를 입력한 경우
x = input.charAt(0) - '0'; // 문자를 숫자로 변환
y = input.charAt(1) - '0';
if( x == 0 && y == 0) // x, y가 모두 0일 때 종료.
break;
}
if(input.length() != 2 || x <= 0 || x >= SIZE || y <= 0 || y >= SIZE ) {
System.out.println("잘못된 입력입니다. 다시 입력해주세요.");
continue;
}
// shipBoard[x-1][y-1]의 값이 1이면, 'o'를 board[x][y]에 저장한다.
board[x][y] = shipBoard[x - 1][y - 1] == 1 ? 'O' : 'X';
// 배열 board의 내용을 화면에 출력한다.
for(int i = 0;i < SIZE; ++i)
System.out.println(board[i]); //board[i]는 1차원 배열
System.out.println();
}
}
}
Note) 실행결과
- 둘이 마주 앉아 다양한 크기의 배를 상대방이 알지 못하게 배치한 다음, 번갈아가며
- 좌료를 불러서 상대방의 배의 위치를 알아내는 게임의 예제이다.
- 2차원 배열 char배열 board는입력한 좌표를 표시하기 위한 것이다.
- 2차원 배열 byte배열 shipBoard에는 상대방의 배의 위치를 저장한다.
- 0은 바다, 1은 배가 있는 것이다.
- char배열이라서 println메서드를 사용가능하다.
'Java > Java의 정석' 카테고리의 다른 글
Chapter 07 객체지향 프로그래밍 II (0) | 2022.02.22 |
---|---|
Chapter 06 객체지향 프로그래밍 I (0) | 2022.02.22 |
Chapter 04 조건문과 반복문 (0) | 2022.02.19 |
Chapter 03 연산자(Operator) (0) | 2022.02.19 |
Chapter 02 변수(Variable) (0) | 2022.02.17 |