[Java] 배열

artp·2025년 1월 17일

java

목록 보기
8/32
post-thumbnail

6. 여러 값 한 번에 저장하기: 배열

6.1 배열의 기본

배열동일한 데이터 타입의 여러 값을 하나의 변수에 저장할 수 있는 자료 구조입니다. 자바에서는 배열을 사용하여 값의 집합을 간단하고 효율적으로 관리할 수 있습니다.

6.1.1 배열이란

배열은 동일한 데이터 타입의 값을 여러 개 저장할 수 있는 자료구조입니다.

  • 각 값은 인덱스를 사용하여 개별적으로 접근할 수 있습니다.
  • 배열의 크기는 한 번 정해지면 변경할 수 없습니다.

예제

int[] numbers = {10, 20, 30, 40}; // 크기가 4인 정수 배열

6.1.2 배열 선언하고 초기화하기

1. 선언

데이터타입[] 배열이름;

또는

데이터타입 배열이름[];

2. 생성

데이터타입[] 배열이름 = new 데이터타입[배열의 크기];

3. 초기화 방법

선언과 동시에 초기화:

int[] numbers = {10, 20, 30};

나중에 초기화:

int[] numbers = new int[3];
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;

6.1.3 배열에 접근하기

배열에 저장된 값을 배열의 요소라고 합니다. 변수는 값이 하나뿐이어서 변수명만으로 값에 접근할 수 있지만, 배열은 요소가 여러 개입니다. 변수명만으로는 원하는 요소에 접근할 수 없습니다. 그래서 배열에서는 요소의 위치를 나타내는 인덱스를 사용합니다.

배열의 요소는 인덱스를 사용하여 접근합니다.

  • 배열의 인덱스는 0부터 시작합니다.
  • 유효하지 않은 인덱스에 접근하면 ArrayIndexOutOfBoundsException이 발생합니다.

예제

public class Main {
	public static void main(String[] args) {
    	int[] numbers = {10, 20, 30};
        
        // 배열의 인덱스는 0부터 시작합니다.
        System.out.println("첫 번째 요소: " + numbers[0]); // 10
        System.out.println("두 번째 요소: " + numbers[1]); // 20
        System.out.println("세 번째 요소: " + numbers[2]); // 30
    }
}

배열에서 특정 값을 변경하기 위해서는 인덱스로 해당 위치에 접근한 후 새로운 값을 저장하면 됩니다.

배열명[인덱스] = 새로운 값;

6.1.4 배열에서 반복문 사용하기

배열은 반복문을 사용하여 손쉽게 모든 요소를 처리할 수 있습니다.

예제 (for 반복문)

public class Main {
	public static void main(String[] args) {
    	int[] numbers = {10, 20, 30};
        
        // 배열의 인덱스는 0부터 시작한다는 점을 고려해서 반복문을 작성합니다.
        for (int i = 0; i < numbers.length; i++) {
        	System.out.println("numbers[" + i + "] = " + numbers[i]);
        }
    }
}

출력

numbers[0] = 10
numbers[1] = 20
numbers[2] = 30

예제 (향상된 for 문)

public class Main {
	public static void main(String[] args) {
    	int[] numbers = {10, 20, 30};
        
        for (int number : numbers) {
        	System.out.println(number);
        }
    }
}

출력

10
20
30

참고: 향상된 for 문

향상된 for 문배열의 모든 요소를 순회할 때 사용합니다.

for (자료형 변수명 : 배열명) {
	실행문; // 배열의 각 요소에 대해 실행
}

6.2 이차원 배열

일차원 배열이 여러 개 모이면 이차원 배열을 구성합니다.
이차원 배열배열 안에 배열이 존재하는 형태입니다. 이차원 배열은 행과 열로 구성됩니다. 엑셀에서의 표나 수학에서 배운 행렬을 생각하면 됩니다.

6.2.1 이차원 배열 선언하고 초기화하기

이차원 배열을 선언할 때는 대괄호 2개([][])를 사용합니다. 이차원 배열을 선언하고 초기화하는 방법은 다음과 같습니다.

선언

데이터타입[][] 배열이름;

또는

데이터타입[][] 배열명 = new 데이터타입[행 크기][열 크기];

초기화

이차원 배열을 선언하고 일차원 배열을 값으로 넣어 초기화합니다.

int[][] array = {
	{1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
}

또는

public class Main {
	public static void main(String[] args) {
    	int[][] array = new int[3][3]; // 3행 3열 배열
		array[0][0] = 1;
		array[0][1] = 2;
		array[0][2] = 3;
		array[1][0] = 4;
		array[1][1] = 5;
		array[1][2] = 6;
		array[2][0] = 7;
		array[2][1] = 8;
		array[2][2] = 9;
    }
}

6.2.2 이차원 배열에 접근하기

이차원 배열의 요소는 행과 열의 인덱스를 사용하여 접근합니다.

예제

public class Main {
	public static void main(String[] args) {
    	int[][] array = {
        	{1, 2, 3},
            {4, 5, 6}
        };
        
        System.out.println("array[0][1] = " + array[0][1]); // 2
	}

예제 (for 문 사용)

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

        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                System.out.print(array[i][j] + " "); // 값 구분을 위해 공백 추가
            }
        }
    }
}

출력

1 2 3 4 5 6

6.2.3 실습: 이차원 배열로 구구단 프로그램 만들기

예제

public class Gugudan {
    public static void main(String[] args) {
        int[][] gugudan = new int[9][9];

        // 배열 초기화
        for (int i = 0; i < gugudan.length; i++) {
            for (int j = 0; j < gugudan[i].length; j++) {
                gugudan[i][j] = (i + 1) * (j + 1);
            }
        }

        // 배열 출력
        for (int i = 0; i < gugudan.length; i++) {
            for (int j = 0; j < gugudan[i].length; j++) {
                System.out.print((i + 1) + "x" + (j + 1) + "=" + gugudan[i][j] + "\t");
            }
            System.out.println();
        }
    }
}

출력

1x1=1   1x2=2   1x3=3   ...   1x9=9
2x1=2   2x2=4   2x3=6   ...   2x9=18
...
9x1=9   9x2=18  9x3=27  ...   9x9=81

6.3 배열 심화

배열은 자바에서 참조 자료형으로, 실제 데이터는 힙(Heap) 메모리에 저장되고, 배열 변수를 통해 그 데이터에 접근합니다. 배열을 복사할 때, 메모리 참조 방식에 따라 얕은 복사(shallow copy)깊은 복사(deep copy)로 나뉩니다.

참조 자료형이란?

  • 참조 자료형은 변수에 실제 데이터가 아닌 메모리 주소(참조값)를 저장합니다.
  • 배열은 힙 영역에 저장되며, 스택 영역에 저장된 배열 변수는 힙 영역의 메모리 주소를 참조합니다.
  • 동일한 메모리 주소를 참조하면 배열의 변경이 서로에게 영향을 미칩니다.

6.3.1 힙과 스택

힙(Heap)

  • 특징

    • 동적으로 할당된 메모리가 저장되는 공간입니다.
    • 배열과 객체가 저장됩니다.
    • 크기가 유동적이며, JVM의 가비지 컬렉터(Garbage Collector)가 메모리를 관리합니다.
  • 배열과 관련

    • 배열의 실제 데이터(값)는 힙에 저장됩니다.
    • 스택에 있는 참조 변수를 통해 힙 영역의 데이터를 참조합니다.

스택(Stack)

  • 특징

    • 메소드 호출 시 생성되며, 메소드 실행이 끝나면 자동으로 제거됩니다.
    • 지역 변수와 참조 변수가 저장됩니다.
    • 크기가 고정되어 있으며, 빠르게 접근할 수 있습니다.
  • 배열과 관련

    • 배열의 이름(참조 변수)은 스택에 저장됩니다.
    • 참조 변수는 힙에 저장된 배열의 메모리 주소를 참조합니다.

메모리 구조 예제

public class MemoryExample {
    public static void main(String[] args) {
        int[] origin = {1, 2, 3}; // origin은 스택에 저장, 배열 데이터는 힙에 저장
        int[] copy = origin;     // copy도 스택에 저장, origin과 같은 힙 주소 참조

        copy[0] = 99;            // 힙 영역의 데이터가 변경됨
        System.out.println("origin[0]: " + origin[0]); // 99
    }
}

메모리 동작

  1. origin 배열 선언:
    • origin 변수는 스택에 저장됩니다.
    • {1, 2, 3} 배열 데이터는 힙에 저장됩니다.
    • origin 변수는 힙 영역의 메모리 주소를 참조합니다.
  2. copy 배열 선언:
    • copy 변수는 스택에 저장됩니다.
    • copyorigin과 같은 힙 메모리 주소를 참조합니다.
  3. copy[0] = 99 수행:
    • 힙 영역의 데이터가 변경됩니다.
    • origincopy 모두 동일한 힙 데이터를 참조하므로 origin[0]도 변경됩니다.

6.3.2 배열의 복사

얕은 복사 (Shallow Copy)

얕은 복사는 메모리 주소만 복사하므로 원본과 복사본이 동일한 데이터를 참조합니다.

  • 동작 방식
    • 배열의 메모리 주소만 복사합니다.
    • 복사된 배열은 원본 배열과 동일한 힙 메모리 주소를 참조합니다.
    • 원본 또는 복사본 배열 중 하나를 변경하면, 다른 배열도 영향을 받습니다.

예제

public class ShallowCopyExample {
    public static void main(String[] args) {
        int[] origin = {1, 2, 3};
        int[] copy = origin; // 메모리 주소 복사 (얕은 복사)

        copy[1] = 88; // 복사본 수정

        // 원본 배열도 영향을 미침
        System.out.println("origin[1]: " + origin[1]); // 88
    }
}

출력

origin[1]: 88

깊은 복사 (Deep Copy)

깊은 복사는 새로운 배열을 생성하고 데이터를 복사하여, 원본과 복사본이 독립적으로 작동합니다.

  • 동작 방식
    • 배열의 메모리 주소가 아닌 배열의 모든 요소를 새로운 배열로 복사합니다.
    • 복사된 배열은 원본 배열과 다른 힙 메모리 주소를 참조합니다.
    • 복사본을 변경해도 원본 배열에는 영향을 미치지 않습니다.

깊은 복사 방법

  1. 수동 복사
   int[] copy = new int[origin.length];
   for (int i = 0; i < origin.length; i++) {
       copy[i] = origin[i];
   }
  1. System.arraycopy 메서드
   System.arraycopy(origin, 0, copy, 0, origin.length);
  1. Arrays.copyOf 메서드
   int[] copy = java.util.Arrays.copyOf(origin, origin.length);

예제: 깊은 복사

public class DeepCopyExample {
    public static void main(String[] args) {
        int[] origin = {1, 2, 3};
        int[] copy = new int[origin.length];

        // 깊은 복사 수행
		for (int i = 0; i < origin.length; i++) {
        	copy[i] = origin[i];
        }

        // 복사본 수정
        copy[0] = 99;

        // 원본 배열은 영향을 받지 않음
        System.out.println("origin[0]: " + origin[0]); // 1
        System.out.println("copy[0]: " + copy[0]);     // 99
    }
}

출력

origin[0]: 1
copy[0]: 99

6.3.3 힙과 스택의 관계

  • 힙(Heap):
    • 배열의 실제 데이터가 저장됩니다.
    • 가비지 컬렉터가 메모리를 관리하며, 참조가 없는 데이터는 자동으로 삭제됩니다.
  • 스택(Stack):
    • 배열 변수(참조 변수)가 저장됩니다.
    • 배열의 메모리 주소를 힙에 전달하여 데이터를 참조합니다.
profile
donggyun_ee

0개의 댓글