공부기록/자바의 정석

[Java의 정석] 5. 배열

박윤서 2022. 4. 1. 01:18

1. 배열(array)

 

1.1 배열이란?

배열은 같은 타입의 여러 변수를 하나의 묶음으로 다루는 것.

int [] score = new int[5];// 5개의 int 값을 저장할 수 있는 배열 생성

여기서 변수 score는 배열을 다루는데 필요한 참조변수일 뿐 값을 저장하기 위한 공간은 아니다.

 

1.2 배열의 선언과 생성

대괄호는 타입 뒤나 변수이름 뒤에 붙이면 된다.

int[] = score; //배열 선언(int 타입의 배열을 다루기 위한 참조변수 score 선언)
score = new int[5] // int타입의 값 5개를 저장할 수 있는 배열

int[] score = new int[5]; //배열의 선언과 생성을 동시에 함. 대부분 경우 이렇게 한다.

배열을 선언하는 것은 생성된 배열을 다루기 위한 참조변수를 위한 공간이 만들어질 뿐임.

배열을 생성해야만 비로소 값을 저장할 수 있는 공간이 만들어진다.

 

1.3 배열의 길이와 인덱스

인덱스는 배열의 요소마다 붙여진 일련번호로 각 요소를 구별하는데 사용된다. 인덱스의 시작은 0부터!

인덱스로 상수 대신 변수나 수식도 사용할 수 있다.

배열을 다룰 때 주의할 점은 인덱스의 범위를 벗어난 값을 인덱스로 사용하지 않아야 한다는 것이다.

컴파일러는 이러한 실수를 걸러주지 못한다. 전적으로 프로그래머의 책임이다.

유효하지 않은 값을 index로 사용하면, ArrayIndexOutOfBoundsException 에러가 발생한다.

배열의 길이는 int범위의 양의 정수(0포함!)이어야 한다. 길이가 0인 배열을 생성할 수 있다.

int[] arr = new int[5];
int tmp = arr.length; //arr.length의 값은 5이며 tmp에 5가 저장된다

//배열은 한번 생성하면 길이를 변경할 수 없기 때문에 상수라고 할 수 있다.
//즉 값을 읽을수만 있을 뿐 변경할 수 없다.
for (int i = 0; i < score.length; i++) {

//for문의 조건식에 배열의 길이를 직접 적어주는 것보다 '배열이름.length'를 사용하는 것이 좋다.

 

-배열의 길이를 변경하는 법

1) 더 큰 배열을 새로 생성한다.

2) 기존 배열의 내용을 새로운 배열에 복사한다.

변경하는 것은 꽤나 비용이 많이 들기 떄문에 처음부터 배열의 길이를 넉넉하게 잡아주는 것이 좋다.

그렇다고 배열의 길이를 너무 크게 잡으면 메모리를 낭비하게 되므로, 기존의 2배정도의 길이로 생성하는 것이 좋다.

 

1.4 배열의 초기화

배열은 생성과 동시에 자동적으로 자신의 타입에 해당하는 기본값으로 초기화되므로 배열을 사용하기 전에 따로 초기화를 해주지 않아도 되지만, 원하는 값을 저장하려면 각 요소마다 값을 지정해 줘야한다.

int[] score = new int[]{50, 60, 70, 80, 90};
int[] score = {50, 60, 70, 80, 90};//생략 가능
// 배열의 선언과 생성을 따로 하는 경우에는 생략할 수 없음.

괄호 안의 값의 개수에 의해 배열의 길이가 자동으로 결정되기 때문에 괄호[] 안에 배열의 길이는 안적어도 된다.

 

int[] arr = { 100, 90, 80, 70, 60};

for(int i = 0; i<arr.length; i++) {
	System.out.println(arr[i]);
}

배열에 저장된 값을 확인할 때 for문을 사용하면 된다.

int [] arr = {100, 90, 80, 70, 60};
System.out.println(Array.toString(arr));

더 간단한 방법으로 Arrays.toString(배열이름) 메서드를 사용하면 된다.

만일 arr의 값을 바로 출력하면 참조변수이기 떄문에 배열의 주소가 출력된다.

그러나 예외적으로 char 배열은 println 메서드로 출력하면 각 요소가 구분자없이 그대로 출력되는데,

이것은 println메서드가 char배열일 때만 이렇게 동작하도록 작성되었기 때문이다.

 

1.5 배열의 복사

배열은 한번 생성하면 길이를 변경할 수 없기 때문에 큰 배열을 새로 만들고 이전 배열로부터 내용을 복사해야함.

1) for문을 이용한 배열 복사 방법

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;

2) System.arraycopy()를 이용한 배열의 복사

지정된 범위의 값들을 한 번에 통째로 복사한다. 

for(int i = 0; i < num.length; i++) { newNum[i] = num[i];}
//arraycopy 문으로 바꾸면
System.arraycopy(num, 0, newNum, 0, num.length);
//num[0] 에서 newNum[0]으로 num.length개의 데이터를 복사

복사하려는 배열의 위치가 적절하지 못하여 복사하려는 내용보다 여유 공간이 적으면 에러가 발생.

 

1.6 배열의 활용

class ArrayEx6 {
	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];
			}
		}			
			System.out.println("최대값 :" + max);
			System.out.println("최소값 :" + min);			
	}
}

배열에 저장된 값에서 최대값과 최소값을 구하는 예제이다.

 

배열을 연속적인 범위의 임의의 값으로 채우는 것은 random만 사용하면 쉽게 할 수 있다.

for(i = 0; i<arr.length;i++) {
	arr[i] = (int)(Math.random()*5);
}
//0~4범위의 임의의 값을 저장
class ArrayEx6 {
	public static void main(String[] args) {
		int[] numArr = new int[10];
		int[] counter = new int[10];
		
		for(int i = 1; i < numArr.length; i++) {
			numArr[i] = (int)(Math.random() * 10);
			System.out.print(numArr[i]);
		}			
		System.out.println();
		
		for(int i =0; i < numArr.length; i++) {
			counter[numArr[i]]++;
		}
		
		for(int i =0; i < num.length; i++) {
			System.out.println( i +"의 개수 :"+  counter[i]);
		}

	}
}

random을 활용하여 빈도수를 구하였다. 배열 counter에서 배열 numArr에 저장된 값과 일치하는 인덱스의 요소에 저장된 값을 1증가시킨다. 이 과정이 반복되고 나면, 배열 counter의 각 요소에는 해당 인덱스의 값이 몇 번 나타났는지 알 수 있는 값이 저장된다.

 

2. String배열

 

2.1 String배열의 선언과 생성

String[] name = new String[3] //3개의 문자열을 담을 수 있는 배열을 생성.

참조형 변수의 기본값은 null이므로 각 요소의 값은 null로 초기화 된다.

 자료형  기본값
boolean  false
char '\u0000' 
byte 0
 short 0
 int
 long 0L 
 float 0.0f 
 double 0.0d 또는 0.0 
 참조형 변수 null 

변수의 타입에 따른 기본값이다.

 

2.2 String배열의 초기화

int배열과 동일한 방법으로 배열의 각 요소에 문자열을 지정하면 된다. 또는 {}를 사용해서 간단히 초기화 할 수도 있다.

String[] name = new String[]{"Kim", "Park", "Yi"};
String[] name = {"Kim", "Park", "Yi"}; //new String 생략 가능

 

2.3 char배열과 String 클래스

String클래스가 char배열에 여러 가지 기능을 추갛여 확장한 것임. 그래서 String클래스를 사용하는 것이 문자열을 다루기 편리하다. String객체(문자열)는 읽을수만 있을 뿐 내용을 변경할 수 없다.

 

-String 클래스의 주요 메서드

1)char charAt(int index)

문자열에서 해당 위치(index)에 있는 문자를 반환한다. charAt메서드의 index값은 0부터 시작한다.

2) int length()

문자열의 길이를 반환한다.

3) String substring(int form, int to)

문자열에서 해당 범위(from~to)에 있는 문자열을 반환한다. 범위의 끝은 포함되지 않는다.

4) boolean equals(Obeject obj)

문자열의 내용이 obj와 같은지 확인한다. 같으면 결과는 true, 다르면 false가 된다. 대소문자를 구분한다!

대소문자를 구분하지 않고 비교하려면 equalsIgnoreCase()를 사용하면 된다.

5) char[]] toCharArray()

문자열을 문자배열(char[])로 변환해서 반환한다.

 

-char 배열과 String클래스의 변환

char[] chArr = {'A', 'B', 'C'};
String str = new String(chArr); // char 배열 -> String
Char[] tmp = str.toCharArray(); //String -> char 배열

 

2.4 커맨드 라인을 통해 입력받기

화면을 통해 사용자로부터 값을 입력받을 수 있다. 

만일 실행할 프로그램의 main메서드가 담긴 클래스의 이름이 MainTest라고 가정하면 다음과 같이 실행할 수 있다.

c:\jdk1.8\work\ch5>java MainTest abc 123

args[0], args[1]과 같은 방식으로 문자열에 접근할 수 있다. args[0]은 "abc"이고 args[1]은 "123"이 된다.

커맨드라인에서 숫자를 입력해도 숫자가 아닌 문자열로 처리된다는 것에 주의해야한다.

JVM이 입력된 매개변수가 없을 때, null 대신 크기가 0인 배열을 생성해서 args에 전달하도록 구현되었다.

 

3. 다차원 배열

메모리의 용량이 허용하는 한, 차원의 제한은 없지만, 주로 1,2차원 배열이 사용된다.

 

3.1 2차원 배열의 선언과 인덱스

2차원 배열을 선언하는 방법은 1차원 배열과 같다. 다만 괄호[]가 하나 더 들어간다.

int[][] score = new int[4][3] // 4행 3열의 2차원 배열을 생성한다.

2차원 배열은 행과 열로 이루어져 있기 때문에 index도 행과 열에 각자 하나씩 존재한다.

 

3.2 2차원 배열의 초기화

int[][] arr = new int[][]{ {1,2,3}, {4,5,6} };
int[][] arr = { {1,2,3} , {4,5,6} };

생성과 초기화를 동시에 했다.

 

3.3 가변 배열

int[][] score = new int[5][3]; //5행 3열의 2차원 배열 생성

--------------------------------------------------------------

int [][] score = new int[5][];
score[0] = new int[4];
score[1] = new int[3];
score[2] = new int[2];
score[3] = new int[2];
score[4] = new int[3];

---------------------------------------------------------------

int[][] score = {
					{100,100,100,100}
                  , {20,20,20}
                  , {30,30}
                  , {40,40}
                  , {50,50,50}
                };   //생성과 초기화를 동시에 함

첫 번째 코드와 같이 2차원 배열을 생성하면 직사각형 테이블 형태의 고정적인 배열만 생성할 수 있지만, 두번째 코드와 같이 2차원 배열을 생성하면 다음과 같이 각 행마다 다른 길이의 배열을 생성하는 것이 가능하다.

 

3.4 다차원 배열의 활용

import java.util.*;

class MultiArrEx4{
	public static void main(String[] args) {
    	String[][] words = {
        	{"chair","의자"},
            {"computer","컴퓨터"},
            {"integer","정수"}
        };
        
        Scanner scanner = new Scanner(System.in);
        
        for(int i = 0;i < words.length; i++) {
        	System.out.printf("Q%d. %s의 뜻은?", i+1, words[i][0]);
            
            String tmp = scanner.nextLine();
            
            if(tmp.equals(words[i][1])) {
            	System.out.printf("정답입니다.%n%n);
            }  else {
            	System.out.printf("틀렸습니다. 정답은 %s입니다. %n%n");
            }
        }
     }
}

영단어를 보여주고 단어의 뜻을 맞추는 예제이다. words[i][0]은 문제이고, words[i][1]은 답이다.