[day04] java-basic : 배열

3 분 소요

1. 배열

1.1 배열이란?

  • 배열이란 연속적인 공간에 같은 타입의 자료들을 모아둔 집합이다.
  • 일일히 변수명을 각자 지정해주는 것이 귀찮고 번거롭기 때문에 컴퓨터에게 변수를 생성하라고 명령하기 위해 생겨난 기능이다.

  • new를 이용해서 만들어진 애들(heap 영역의 아이들)은 대부분 객체라고 한다.
  • 배열도 new 키워드를 통해서 만들어지기 때문에 객체라고 할 수 있다.
  • heap영역에는 변수명이 저장되지 않고 주소값만 저장되기 때문에, stack영역에 주소값을 기억하고 있는 참조변수가 필요하다.

  • 배열을 쓴다고 필요한 메모리 공간이 줄어들지는 않는다.
  • 배열을 쓰던 각자 저장하던, int 자료 4개를 저장하려면 4byte의 heap 저장공간이 4개 필요한 것은 동일하다.
  • 다만, 변수를 하나 만들때마다 컴퓨터는 변수 갯수 만큼 주소값을 일일히 전부 기억해야 하지만,
  • 배열은 연속적인 공간에 4개의 변수가 저장되어 있기 때문에 하나의 주소값만 기억하면 된다.
  • 왜냐하면 배열은 연속적인 공간으로 이루어져있기 때문에 하나의 주소값만 알면 byte크기만큼 계산해서 각 요소의 주소값을 유추할 수 있기 때문이다.

  • 배열에서는 첫번째 요소의 주소값에서부터 같은 타입의 변수가 몇 개 떨어져 있는지 상대적인 숫자로 접근할 수 있다.
  • 이를 즉 배열의 index라고 한다.
  • index가 0부터 시작하는 이유는 [첫 번째 요소는 주소값으로부터 0칸 / 두번째 요소는 주소값으로부터 1칸….] 이런식으로 구성되어 있기 때문이다.

  • 배열은 크기를 수정할 수 없기 때문에 자바에서는 배열보다는 List를 더 많이 사용한다.

1.2 배열의 선언

  • []은 자바에서 배열을 나타낸다.
  • []를 하나만 쓰면 일차원배열, [][]두 개를 쓰면 이차원 배열이다.

  • 배열의 참조변수 선언방식 : 배열유형(데이터타입) 배열이름(참조변수) [] OR 배열유형(데이터타입) [] 배열이름(참조변수)

  • 배열의 유형은 기본형이던 참조형이던 모두 가능하다.
  • 배열이름은 stack영역에 저장되며 heap영역의 주소값을 기억하는 참조변수이다.

  • haep 영역의 공간을 생성하는 키워드는 new이므로, new int[4]; 형식으로 new키워드가 없으면 heap영역의 배열 저장 공간이 생기지 않는다.
  • 배열, String같이 프로그램을 실행하기 전까지는 JVM이 얼마만큼 크기의 메모리 공간을 확보해야할지 모르는 것들은 new키워드를 사용해서 heap영역을 만들어줘야 한다.
  • 배열을 온전히 생성+초기화하려면 int[] arr = new int[4]; 의 형식으로 작성해야 한다.

  • new키워드를 통해서 만들어진 공간은 전부 자동으로 초기화가 발생한다.
  • 그래서 배열을 heap영역에 만들면 정수배열은 모든값이 int 0으로 자동 초기화된다.
  • boolean = false, char = '\u0000', float = 0.0, 참조형= null로 자동 초기화된다.
  • 자동 초기화 하지 않고, 다른 값으로 초기화하려면 int[4] arr = {1, 2, 3, 4};로 직접 각 요소 값을 지정해주면 된다.

  • ‘배열생성 + 다른 값으로 초기화’ 하려면, int[] arr = new int[]{1, 2, 3, 4};으로 작성할 수 있다.

  • int[4] arr = {1, 2, 3, 4};int[] arr = new int[]{1, 2, 3, 4};의 차이는? : 앞의 것은 기존 참조변수에 대입될 수 없지만, 뒤의 방식은 가능하다.

  • 배열의 초기화 형식 : 배열이름[인덱스번호] = 값

  • 배열이 가진 모든 요소들을 출력하는 방식 3가지
  1. index를 이용한 출력 : for문과 length 활용하기
  2. foreach문 이용한 출력 : JDK 1.5버전 이후만 사용 가능
  3. Arrays.toString() 메소드를 이용한 출력
    • java.utill에 속한 메소드로 배열을 문자열로 만들어서 출력해준다.

1.3 이차원배열

  • 이차원배열의 선언+ 초기화 : int[][] arr = new int[일차원배열의 개수][각 일차원배열의 원소 개수];
  • 이차원배열은 1차원 배열의 집합이다.
  • 그래서 이차원배열은 1차원 배열들의 주소값을 1차원 배열 형태로 기억한다. image

  • 만약 int[][] arr = new int[3][]이라면 arr[0], arr[1], arr[2]에는 arr[][]의 주소값들이 null로 저장되어 있다.

  • 이차원배열에서 크기를 반환해주는 length를 사용할 수 있을까? YES!
int[][] arr2 = new int[3][8];
System.out.println( arr2.length ); // result : 3
System.out.println( arr2[1].length ); // result : 8
  • 이차원배열은 int[][] arr = { {}, {}, {} }으로 초기화하면 된다.
  • 하지만 java에서는 객체지향을 따르기 때문에 이차원배열을 거의 사용하지 않는다.

1.4 참조형 배열 (String)

  • 참조자료형 일차원 배열은 이차원 배열 구조를 가진다.
  • 왜냐하면 참조자료형은 String[] strArr = {new String("vh"),new String("epd"),new String("dd")};의 형식으로 배열이 만들어지기 때문이다.
  • 그림을 그려서 이해해보자면,

1.5 배열의 복사

int[] a = {10, 20, 30};
int[] b = a;
  • 위의 경우, b에는 a배열의 heap영역 주소값이 저장된다. shallow copy(얕은 복사)
  • 참조변수만 복사되기 때문이다.

  • 똑같은 배열을 heap 영역에 하나 더 만들고 싶다면 deep copy(깊은 복사)를 해야한다.
  • 이때, new 키워드로 같은 크기의 배열을 만들고 각 index에 같은 값을 채워주면 된다.

  • System.arraycopy()는 자바가 제공하는 API이다.
  • ()안에는 복사하려는 (배열명, 복사 시작 지점, 복사 당할 배열명, 복사 당하기 시작할 지점, 복사 끝 지점) 순으로 작성된다?

  • foreach문을 통해 배열안의 요소값을 조작해봤자 shallow copy되기 때문에 원본 배열의 값은 변하지 않는다.
// a배열의 모든 요소에 100을 더하기

for(int num : a) {
  num = num + 100;
  System.out.println(num);
}

System.out.println("--------------- 배열 원본 출력 ----------------");
for(int num : a) {
  System.out.println(num);
}
  • foreach문은 num 변수를 활용해 값을 출력하기만 할 뿐, 원본의 값은 변경시킬 수 없다.
  • int num은 stack 메모리에 만들어져서 원본의 값이 저장되기만 하기 때문이다.