JAVA/Java Start

8. 배열 Array

Toughie 2024. 2. 2. 13:19

지금까지는 단순한 변수에 값을 할당하는 방식으로 데이터를 관리했었다.

하지만 여러 비슷한 변수들이 필요한 경우, 변수의 양이 굉장히 많은 경우 비효율적인 상황이 생길 수 있다.

public class Array1 {

    public static void main(String[] args) {
        int student1 = 90;
        int student2 = 80;
        int student3 = 70;
        int student4 = 60;
        int student5 = 50;
        //학생을 한 명 더 추가한다면
        int student6 = 40;
    
        //반복문으로 해결할 수 없나?
        for(int i=1; i <=6; i++) {
            System.out.println("학생" + i + "점수" + student1);
        }
        //변수명까지 i를 활용할 수는 없다..
        
        System.out.println("학생1 점수: "+ student1);
        System.out.println("학생2 점수: "+ student2);
        System.out.println("학생3 점수: "+ student3);
        System.out.println("학생4 점수: "+ student4);
        System.out.println("학생5 점수: "+ student5);

        System.out.println("학생6 점수: "+ student6);
    }
}

 

위와 같은 상황에서 배열을 활용하면 더욱 효율적인 코드를 작성할 수 있다.

배열은 같은 타입의 변수를 하나로 묶어둔 것이다.

(여러 타입의 변수를 담으려면 ArrayList를 사용해야 한다. Array는 전부 같은 타입의 요소만 담을 수 있다.)


기본형과 참조형

기본형(Primitive Type)

 

int, long, double, boolean처럼 변수에 사용할 값을 직접 넣는 데이터 타입.

기본형은 데이터의 사이즈가 명확하게 정해져 있다. (int는 4바이트, double은 8바이트)

 

참조형(Reference Type)

 

int[] students와 같이 데이터에 접근하기 위한 참조(주소)를 저장하는 데이터 타입 (객체, 클래스를 담는 변수)

 

배열은 왜 참조를 해야 할까?

기본타입은 선언과 동시에 사이즈가 정해지기 때문에 정적 할당이 이루어진다. (컴파일 타임)

(그렇기 때문에 더 빠르고 효율적인 메모리 사용이 가능하다.)

 

하지만 배열의 사이즈는 바뀔 수 있기 때문에 동적 메모리 할당의 가능성이 있다. (런 타임)

(ex. Scanner를 통해 배열의 사이즈를 프로세스에서 받는 경우)

즉 참조형을 활용하면 더 유연한 메모리 할당이 가능한 것이다. (new 키워드를 통한 객체 인스턴스 생성)


1차원 배열 초기화와 인덱싱

 public static void main(String[] args) {
        int[] students; //배열 주소를 담을 변수 선언
        students = new int[3];
//        students = new int[]; 배열의 사이즈를 누락한 경우 array dimension missing

        // 배열의 크기 만큼 메모리 공간을 확보(int의 경우 4byte * 3)
        // 배열 생성 후 배열의 참조값(주소)가 students 변수에 담긴다.
        // [I@3f99bd52  -- 정수 배열, 16진법 표기

        //3개의 int공간이 생성, 0으로 *자동 초기화
        //숫자는 0, boolean은 false, String은 null로 자동 초기화
		
        //배열의 사이즈를 벗어나는 경우_Swift에서의 index out of range
//        Index 5 out of bounds for length 5 at array.
		
        //인덱싱을 통한 배열 값 변경
        students[0] = 90;
        //[I@3f99bd52 참조값을 통해 실제 배열에 접근, 인덱스를 사용해서 해당 위치 요소에 접근 후 값 대입
        students[1] = 80;
        students[2] = 70;

        System.out.println("학생1 점수: "+ students[0]);
        System.out.println("학생2 점수: "+ students[1]);
        System.out.println("학생3 점수: "+ students[2]);

        System.out.println(students);
    }
 public static void main(String[] args) {

        int[] students = new int[5];
        int arraySize = students.length;
//        int[] students = new int[]{90, 80, 70, 60, 50}; //배열 생성과 초기화
//        int[] students = {90, 80, 70, 60, 50}; // 타입 추론 초기화
//        왜 중괄호를 쓰는 지 궁금했지만 그냥 java 문법인 것 같다.
        
        // 사이즈 5의 배열에 3개의 초기값을 주면 나머지는 0으로 자동 초기화 되나 싶었지만..
        // array creation with both dimension expression and initialization is illegal
//        int[] testArray = new int[5]{1,2,3};

        for (int i = 0; i < students.length; i++) {
            students[i] = 100 - (10 * (i + 1));
        }

        for (int i = 0; i < students.length; i++) {
            System.out.println("학생 " + (i + 1) + " 점수 = " + students[i]);
        }

        System.out.println(students);
    }

2차원 배열

row(행) column(열)

    public static void main(String[] args) {
        //2 x 3 배열
        int[][] arr = new int[2][3];
        // 0 0 0
        // 0 0 0 이렇게 초기화

//      [[1, 2, 3], [4, 5, 6]] 파이썬 문법으로 본다면

        arr[0][0] = 1; //0행 0열
        arr[0][1] = 2; //0행 1열
        arr[0][2] = 3; //0행 2열
        arr[1][0] = 4; //1행 0열
        arr[1][1] = 5; //1행 1열
        arr[1][2] = 6; //1행 2열
        
        // 1 2 3
        // 4 5 6
        System.out.print(arr[0][0] + " ");
        System.out.print(arr[0][1] + " ");
        System.out.println(arr[0][2] + " ");
        System.out.print(arr[1][0] + " ");
        System.out.print(arr[1][1] + " ");
        System.out.print(arr[1][2] + " ");
    }

 

초기값을 통한 초기화, 2중 for문을 활용한 개선 (배열과 기본적으로는 동일하다)

    public static void main(String[] args) {

        int[][] arr = new int[2][3];

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

        for (int i = 0; i < row; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                arr[i][j] = (i * 3) + (j + 1);
            }
        }

        for (int i = 0; i < row; i++) {
            for (int j = 0; j < 3; j++) {
                System.out.print(arr[i][j] + " ");
            }
            System.out.println();
        }
    }

 

+ 3차원 배열의 경우에는 면, 행, 열로 생각할 수 있다. 

int[][][] triple = new int[3][3][3];

Enhanced For (For Each)

인덱스를 사용하지 않고, 종료 조건도 없이 배열의 요소를 전부 탐색할 수 있는 편리한 반복문.

하지만 인덱싱이 필요한 경우에는 일반 반복문을 사용하는 편이 효율적이다.

    public static void main(String[] args) {
        int[] numbers = {1, 2, 3, 4, 5};
        //단축키 iter

        //일반 for문
        for (int i = 0; i < numbers.length; i++) {
            System.out.print(numbers[i] + " ");
        }
        System.out.println();
        // for-each 배열의 요소를 순차적으로 순회한다.
        // numbers 배열의 각 요소에 대한 값의 복사본이 number로
        for (int number : numbers) {
            System.out.print(number + " ");
        }
    }

Scanner, Array, Switch 활용 예시

보통 객체에 담아서 데이터를 관리하겠지만, 단일 배열을 활용한 예시

import java.util.Scanner;

// 상품 등록: 상품 이름과 가격을 입력받아 저장.
// 상품 목록: 지금까지 등록한 모든 상품의 목록 출력

// 첫 화면에서 사용자에게 세 가지 선택 제시 1. 상품 등록, 2. 상품 목록, 3.종료
// 1번은 사용자로부터 상품 이름과 가격을 입력받아 배열에 저장한다.
// 2번은 배열에 저장된 모든 상품을 출력한다.
// 3. 종료를 선택하면 프로그램 종료
// 상품은 최대 10개까지 등록할 수 있다.
public class ArrayEx8 {
    public static void main(String[] args) {
        boolean active = true;

        Scanner scanner = new Scanner(System.in);
        int maxProducts = 3;

        String[] productNames = new String[maxProducts];
        int[] productPrice = new int[maxProducts];
        int productCount = 0;

        while (active) {
            System.out.print("1. 상품 등록 | 2. 상품 목록 | 3. 종료\n메뉴를 선택하세요: ");
            //숫자만 입력한다는 가정
            int option = scanner.nextInt();
            //입력 버퍼 비우기 \n
            scanner.nextLine();

            switch (option) {
                case 1:

                    if (productCount >= maxProducts) {
                        System.out.println("더 이상 상품을 등록할 수 없습니다.");
                        continue;
//                        break;
                    }
                    System.out.print("상품 이름을 입력하세요: ");
                    productNames[productCount] = scanner.next();
                    System.out.print("상품 가격을 입력하세요: ");
                    productPrice[productCount] = scanner.nextInt();

                    productCount++;
                    break;
                case 2:
                    if (productCount == 0) {
                        System.out.println("등록된 상품이 없습니다.");
                        continue;
                    }
                    for (int i = 0; i < productCount; i++) {
                        System.out.printf("%s : %d 원\n", productNames[i], productPrice[i]);
                    }
                case 3:
                    System.out.println("프로그램을 종료합니다.");
                    active = false;
                default:
                    System.out.println("잘못된 메뉴를 입력하셨습니다.");
                    break;
            }
        }
    }
}

 

 

학습 출처

김영한의 자바 입문 - 코드로 시작하는 자바 첫걸음