과정을 즐기자

Java에서 배열이 객체인 이유와 메모리 할당에 대해서 본문

Java

Java에서 배열이 객체인 이유와 메모리 할당에 대해서

320Hwany 2024. 1. 13. 15:23

가장 기본적인 자료 구조 중 하나로 배열이 있습니다.   

배열은 미리 일정 크기만큼 메모리를 할당한 후 데이터를 순차적으로 저장하는 자료구조입니다.

Java 에서의 배열

Java에서는 다음과 같이 배열을 생성하고 사용할 수 있습니다.

int[] array1 = new int[5];

32 비트 정수형 데이터 타입인 int를 총 5개를 미리 메모리에 할당합니다.

물론 선언을 할 때 원소를 미리 저장할 수도 있습니다.

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

 

그렇다면 이러한 배열과 내부 원소들은 메모리의 어디 부분에 할당되는 것일까요?

배열도 객체다

Java에서는 배열도 객체라고 할 수 있습니다. 배열을 생성할 때는 다른 객체 생성과 마찬가지로 new 키워드를 이용해서

배열을 생성합니다. 앞에서 살펴본 예시처럼 사용할 수 있습니다. 

 

또한 Java에서 모든 객체는 Object 클래스를 상속 받습니다. 즉 모든 클래스는 Object의 equals(), hashCode(),

toString(), clone()와 같은 메소드를 재정의 및 사용할 수 있습니다.

boolean equals = array1.equals(array2);
int i = array1.hashCode();
String s = array1.toString();
int[] clone = array1.clone();

 

배열에 대한 객체가 존재한다는 것은 배열에 대한 클래스 타입이 존재한다는 것입니다.

대표적인 몇 개의 예시로 클래스 타입을 확인해보겠습니다.

int[] array1 = new int[5];
Integer[] array2 = new Integer[5];
long[] array3 = new long[5];
Long[] array4 = new Long[5];
String[] array5 = new String[5];

System.out.println(array1.getClass());
System.out.println(array2.getClass());
System.out.println(array3.getClass());
System.out.println(array4.getClass());
System.out.println(array5.getClass());

 

공통적으로 배열에 대한 클래스 타입은 '[' 기호로 시작합니다. 배열의 차원마다 '['가 하나씩 추가됩니다.

Primitive type은 '[' 뒤에 다음과 같은 기호가 붙습니다.

  • B : byte
  • C : char
  • D : double
  • F : float
  • I : int
  • J : long
  • S : short
  • Z : boolean

Reference type은 '[' 뒤에 'L' 기호가 붙고 ';'으로 끝납니다.

메모리의 어디에 저장될까

Java는 기본적으로 Call By Value 입니다. 이에 대한 내용은 이전 글을 참고해주세요.

 

자바가 Call By Reference가 아닌 이유

프로그래밍 언어를 공부하다보면 Call By Value, Call By Reference 라는 용어가 자주 들립니다. Call By Value는 값을 전달하는 방식이고 Call By Reference는 주소를 전달하는 방식입니다. 그렇다면 자바는 어떤

320hwany.tistory.com

간단히 요약해보자면 Primitive type의 경우에는 메모리 Stack 영역에 저장되고 Reference type의 경우에는

객체에 대한 주소값은 Stack에 저장되고 이 Stack의 주소값을 이용하여 Heap에 있는 객체에 접근합니다. 

 

배열의 경우에는 배열 자체는 객체이기 때문에 Reference type처럼 배열 객체에 대한 주소값은 Stack 영역에

배열은 Heap 영역에 저장된다고 할 수 있습니다. 예시를 들어 설명해보겠습니다.

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

 

array1을 가리키는 주소값은 Stack 영역에 저장되고 array1의 객체는 Heap 영역에 저장됩니다.

이때 1가지 의문점이 들 수 있습니다. 1, 2, 3, 4, 5는 Primitive type으로 원래는 Stack 영역에 저장됩니다.

하지만 이 경우에는 배열의 원소이기 때문에 미리 할당된 Heap 영역에 저장되는 것입니다.

그렇다면 배열의 원소도 Reference type인 경우는 어떨까요?

다음과 같은 Member 클래스를 먼저 정해봤습니다.

static class Member {
    String name;
    int age;

    public Member(final String name, final int age) {
        this.name = name;
        this.age = age;
    }
}

 

members 배열을 선언해줍니다.

Member[] members = new Member[]{member1, member2};

 

배열의 원소가 Reference type인 경우에는 Stack에 members의 주소값이 저장되어 있고 Heap 영역에는

원소인 member1, member2의 주소값이 저장되어 있습니다.

여기서 Stack 영역의 member1, member2의 주소값은 있을 수도 있고 없을 수도 있습니다.