[Java] Java의 정석 | Chapter 05 배열 array

숙취엔 꿀물.·2023년 11월 30일

Java

목록 보기
5/13
post-thumbnail

👉 1. 배열(array)

1.1 배열(array)이란?

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

중요한 것은 반드시 '같은 타입'이어야 한다는 것이며, 서로 다른 타입의 변수들로 구성된 배열은 만들 수 없다.


1.2 배열의 선언과 생성

선언방법선언 예
타입[] 변수이름;int[] score; String[] name;
타입 변수이름[];int score[]; String name[];

배열의 생성

배열을 선언하는 것은 단지 생성된 배열을 다루기 위한 참조변수를 위한 공간이 만들어질 뿐이고, 배열을 생성해야만 비로소 값을 저장할 수 있는 공간이 만들어지는 것이다.

타입[] 변수이름;			 // 배열을 선언(배열을 다루기 위한 참조변수 선언)
변수이름 = new 타입[길이]; // 배열을 생성(실제 저장공간을 생성)

'길이가 5인 int 배열'을 생성하면 아래와 같다. 또, 배열의 선언과 생성을 동시에 한 줄로 할 수도 있다.

int[] score;
score = new int[5];

타입[] 변수이름 = new 타입[길이];	// 배열의 선언과 생성을 동시에
int[] score = new int[5];	   // 길이가 5인 int 배열

1.3 배열의 길이와 인덱스

  • 생성된 배열의 각 저장공간을 '배열의 요소(element)'라고 하며, '배열이름[인덱스]'의 형식으로 배열의 요소에 접근한다.

  • 인덱스(index)는 배열의 요소마다 붙여진 일련번호로 각 요소를 구별하는데 사용된다.

    	"인덱스(index)의 범위는 0부터 '배열길이-1'까지."
  • 배열의 또 다른 장점은 index로 상수 대신 변수나 수식도 사용할 수 있다는 것이다.

배열을 다룰 때 주의할 점은 유효한 범위를 벗어난 값을 index로 사용하면, 무사히 컴파일을 마쳤더라도 실행 시에 에러(ArrayIndexOutOfBoundsException)가 발생한다.

public class ArrayEx1 {
    public static void main(String[] args) {
        int[] score = new int[5];
        int k = 1;

        score[0] = 50;
        score[1] = 60;
        score[k + 1] = 70;
        score[3] = 80;
        score[4] = 90;

        int tmp = score[k + 2] + score[4];

        // for문으로 배열의 모든 요소를 출력한다.
        for (int i = 0; i < 5; i++) {
            System.out.printf("score[%d] : %d\n", i, score[i]);
        }

        System.out.printf("tmp:%d\n", tmp);
        System.out.printf("score[%d] : %d\n", 7, score[7]); // index의 범위를 벗어난 값
    }
}

배열의 길이

  • 배열의 길이는 양의 정수이어야 하며 최대값은 int타입의 최대값, 약 20억이다.
  • 참고로 길이가 0인 배열도 생성이 가능하다.(어느 경우에서 쓰이는지는 이후에..)

배열이름.length

자바에서는 JVM이 모든 배열의 길이를 별도로 관리하며, 배열이름.length를 통해서 배열의 길이에 대한 정보를 얻을 수 있다.

  • 배열은 한번 생성하면 길이를 변경할 수 없기 때문에, 이미 생성된 배열의 길이는 변하지 않는다.
  • 따라서 배열이름.length는 상수다. 즉, 값을 읽을 수만 있을 뿐 변경할 수 없다.

배열의 길이 변경하기

배열의 길이를 변경하는 방법:
	1. 더 큰 배열을 새로 생성한다.
    2. 기존 배열의 내용을 새로운 배열에 복사한다.
    + 혹은 가변배열을 사용한다 정도가 되겠다.

1.4 배열의 초기화

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

int[] score = new int[5];
score[0] = 50; score[1] = 60; score[2] = 70; score[3] = 80; score[4] = 90;

// or

int[] score = new int[]{50, 60, 70, 80, 90}; // new int[]는 생략 가능하다

// or

for(int i=0; i < score.length; i++)
	score[i] = i * 10 + 50;
  • 만약 배열의 선언과 생성을 따로 한다면 new int[]는 생략할 수 없다.

배열의 출력

public class ArrayEx2 {
    public static void main(String[] args) {
        int[] iArr1 = new int[10];
        int[] iArr2 = new int[10];
        // int[] iArr3 = new int[]{100, 95, 80, 70, 60};
        int[] iArr3 = {100, 95, 80, 70, 60};
        char[] chArr = {'a', 'b', 'c', 'd'};

        for (int i = 0; i < iArr1.length; i++) {
            iArr1[i] = i + 1; // 1~10의 숫자를 순서대로 배열에 넣는다.
        }

        for (int i = 0; i < iArr2.length; i++) {
            iArr2[i] = (int) (Math.random() * 10) + 1; // 1~10의 값을 배열에 저장
        }

        // 배열에 저장된 값들을 출력한다.
        for (int i = 0; i < iArr1.length; i++) {
            System.out.print(iArr1[i] + ", ");
        }

        System.out.println();
        System.out.println(Arrays.toString(iArr2));
        System.out.println(Arrays.toString(iArr3));
        System.out.println(Arrays.toString(chArr));
        System.out.println(iArr3);
        System.out.println(chArr);
    }
}

1.5 배열의 복사

  1. for문의 이용
public class ArrayEx3 {
    public static void main(String[] args) {
        int[] arr = new int[5];

        // 배열 arr에 1~5를 저장한다.
        for (int i = 0; i < arr.length; i++)
            arr[i] = i + 1;

        System.out.println("[변경전]");
        System.out.println("arr.length:" + arr.length);
        for (int i = 0; i < arr.length; i++)
            System.out.println("arr[" + i + "]:" + arr[i]);

        int[] tmp = new int[arr.length * 2];

        // 배열 arr에 저장된 값들을 배열 tmp에 복사한다.
        for (int i = 0; i < arr.length; i++)
            tmp[i] = arr[i];

        arr = tmp;

        System.out.println("[변경후]");
        System.out.println("arr.length:" + arr.length);
        for (int i = 0; i < arr.length; i++)
            System.out.println("arr[" + i + "]:" + arr[i]);
    }
}
  1. System.arraycopy()를 이요한 배열의 복사
System.arrcopy(num, 0, newNum, 0, num.length);

-> num[0]에서 newNum[0]으로 num.length개의 데이터를 복사 한다는 뜻이다.


1.6 배열의 활용

  • 각 예제에 대한 설명은 따로 하지 않도록 하겠다..

[예제 5-6] 최대값과 최소값

public 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);
    }
}

[예제 5-10] 정렬하기(sort)

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));
        }
        Systme.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();
        }
    }
}

[예제 5-11] 빈도수 구하기

public class ArrayEx11 {
    public static void main(String[] args) {
        int[] numArr = new int[10];
        int[] counter = new int[10];

        for (int i = 0; i < numArr.length; i++) {
            numArr[i] = (int) (Math.random() * 10); // 0~9의 임의의 수를 배열에 저장
            System.out.print(numArr[i]);
        }
        System.out.println();

        for (int i = 0; i < numArr.length; i++) {
            counter[numArr[i]]++;
        }

        for (int i = 0; i < numArr.length; i++) {
            System.out.println(i + "의 개수 : " + counter[i]);
        }
    }
}


👉 2. String 배열

2.1 String 배열의 선언과 생성

배열의 타입이 String인 경우에도 int배열의 선언과 생성방법은 다르지 않다.

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

참고로 변수의 타입에 따른 기본값은 다음과 같다.

자료형기본값
booleanfalse
char'\u0000'
byte,short,int0
long0L
float0.0f
double0.0d 또는 0.0
참조형 변수null

2.2 String 배열의 초기화

초기화 역시 int배열과 동일한 방법으로 한다. 아래와 같이 배열의 각 요소에 문자열을 지정하면 된다.

String[] name = new String[3]; // 길이가 3인 String배열을 생성
name[0] = "Kim"; name[1] = "Park"; name[2] = "Yi";

// or

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

특별히 String 클래스만 "Kim"과 같이 큰따옴표만으로 간략히 표현하는 것이 허용되지만, 원래 String은 클래스이므로 아래의 왼쪽처럼 new연산자를 통해 객체를 생성해야한다.

  • 배열에 실체 객체가 아닌 객체의 주소가 저장되어 있다.
  • 이처럼, 기본형 배열이 아닌 경우, 즉, 참조형 배열의 경우 배열에 저장되는 것은 객체의 주소이다.

2.3 char 배열과 String 클래스

String 클래스는 char 배열에 기능(메서드)을 추가한 것이다.

주요 메서드설명
char charAt(int index)문자열에서 해당 위치(index)에 있는 문자를 반환한다.
int length()문자열의 길이를 반환한다.
String substring(int from, int to)문자열에서 해당 범위(from~to)에 있는 문자열을 반환한다.(to는 범위에 포함되지 않음)
boolean equals(Object obj)문자열의 내용이 obj와 같은지 확인한다. 같으면 결과는 true, 다르면 false가 된다.
char[] toCharArray()문자열을 문자배열(char[])로 변환해서 반환한다.

char 배열과 String 클래스의 변환

가끔 char배열을 String클래스로 변환하거나, 또는 그 반대로 변환해야하는 경우가 있다. 그럴 때 다음의 코드를 사용하자.

char[] chArr = {'A', 'B', 'C'};

String str = new String(chArr);	// char 배열 -> String
char[] tmp = str.toCharArray(); // String -> char 배열

ex) 문자열(String)을 모르스(morse)부호로 변환하는 예제

public class ArrayEx15 {
    public static void main(String[] args) {
        String source = "SOSHELP";
        String[] morse = {".-", "-...", "-.-.", "-..", "."
                , "..-.", "--.", "....", "..", ".---"
                , "-.-", ".-..", "--", "-.", "---"
                , ".--.", "--.-", ".-.", "...", "-"
                , "..-", "...-", ".--", "-..-", "-.--"
                , "--.."};
        String result = "";

        for (int i = 0; i < source.length(); i++) {
            result += morse[source.charAt(i) - 'A'];
        }

        System.out.println("source:" + source);
        System.out.println("morse:" + result);
    }
}

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

  • 프로그램을 실행할 때 클래스 이름 뒤에 공백문자로 구분하여 여러 개의 문자열을 프로그램에 전달 할 수 있다.

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

    	c:\jdk1.8\work\ch5>java MainTest abc 123
  • 커맨드라인을 통해 입력된 두 문자열을 String배열에 담겨서 MainTest클래스의 main메서드의 매개변수 args 에 전달된다.

  • 그리고는 main메서드 내에서 args[0], args[1]과 같은 방식으로 커맨드라인으로부터 전달받은 문자열에 접근할 수 있다.



👉 3. 다차원 배열

지금까지 우리가 배운 배열은 1차원 배열인데, 2차원 이상의 배열, 즉 다차원(multi-dimensional) 배열도 선언해서 사용할 수 있다.

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

선언 방법은 1차원과 같다. 다만 괄호[]가 하나 더 들어갈 뿐이다.

선언 방법선언 예
타입[][] 변수이름;int[][] score;
타입 변수이름[][];int score[][];
타입[] 변수이름[];int[] score[];

만일 4행 3열의 데이터를 담기 위한 배열을 생성하려면 다음과 같이한다.

int[][] score = new int[4][3];

2차원 배열의 index

  • 2차원 배열은 행(row)과 열(column)로 구성되어 있기 때문에 index도 행과 열에 각각 하나씩 존재한다.

  • 행index의 범위 : 0~행의길이 -1 / 열index의 범위 : 0~열의 길이 -1

  • 각 요소에 접근하는 방법 : 배열이름[행index][열index]


3.2 2차원 배열의 초기화

int[][] arr = new int[][]{ {1,2,3}, {4,5,6} }; // new int[][]는 생략 가능

// or

int[][] arr = {
				{1,2,3},
                {4,5,6}
              };
  • for문을 이용해서 2차원 배열을 초기화 할수도 있다. (2차원 배열 score의 모든 요소를 10으로 초기화)
for(int i=0; i<score.length; i++){
	for(int j=0; j<score[i].length; j++){
    	score[i][j] = 10;
    }
}

3.3 가변 배열

2차원 이상의 다차원 배열을 생성할 때 전체 배열 차수 중 마지막 차수의 길이를 지정하지 않고, 추후에 각기 다른 배열을 생성함으로써 고정된 형태가 아닌 보다 유동적인 가변 배열을 구성할 수 있다.

int[][] score = new int[2][]; // 두 번째 차원의 길이는 지정하지 않는다.
score[0] = new int[3];
score[1] = new int[3];

// or

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

위와 같이 각 행마다 다른 길이의 배열을 생성하는 것도 가능하다.


3.4 다차원 배열의 활용

[예제 5-22] 행렬의 곱셈 - 두 행렬(matrix)을 곱한 결과를 출력

public class MultiArrEx3 {
    public static void main(String[] args) {
        int[][] m1 = {
                {1, 2, 3},
                {4, 5, 6}
        };

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

        final int ROW = m1.length;      // m1의 행 길이
        final int COL = m2[0].length;   // m2의 열 길이
        final int M2_ROW = m2.length;   // m2의 행 길이

        int[][] m3 = new int[ROW][COL];

        // 행렬곱 m1 x m2의 결과를 m3에 저장
        for (int i = 0; i < ROW; i++)
            for (int j = 0; j < COL; j++)
                for (int k = 0; k < M2_ROW; k++)
                    m3[i][j] += m1[i][k] * m2[k][j];

        // 행렬 m3를 출력
        for (int i = 0; i < ROW; i++) {
            for (int j = 0; j < COL; j++) {
                System.out.printf("%3d ", m3[i][j]);
            }
            System.out.println();
        }
    }
}

이 외에도 배열의 활용은 무궁무진하다.

profile
단단하게 오래가고자 하는 백엔드 개발자

0개의 댓글