자바 객체 배열 | 자바 입문강좌 18

자바 객체 배열

배열(Array)은 같은 자료형을 연속되게 사용하는 시스템입니다. 그런데 자바는 객체지향프로그래밍으로 모든 프로그램을 객체를 중심으로 작성합니다. 객체 역시 하나의 자료형입니다.

그렇다면 궁금증이 객체도 배열로 만들 수 있는가? 입니다.

자바 객체 배열
자바 객체 배열

정답은 만들 수 있습니다.

자바에는 기본 자료형과 참조 자료형이 있습니다. 이 두 자료형의 차이점을 이해하는 것이 일반 배열(Array)과 객체 배열(Array of Objects)의 차이를 구분하도록 할 것 입니다.

클래스를 만들어서 알아보겠습니다. 아래는 myObject 클래스를 하나 만들고 이 클래스를 3개 담을 수 있는 객체 배열을 하나 생성합니다.

public class Main {
    public static void main(String[] args) {
        myObject[] arrayObj = new myObject[3];

        for (int i = 0; i < arrayObj.length; i++) {
            System.out.println("arrayObj["+i+"] = " + arrayObj[i]);
        }
    }
}
class myObject{
    int id;
    String description;
    myObject(){
    }
}
[실행값]
arrayObj[0] = null
arrayObj[1] = null
arrayObj[2] = null

배열은 length 를 사용하여 사이즈를 측정할 수 있는데 객체도 마찬가지입니다. length를 이용하여 for 루프를 돌려보면 3개의 배열 공간이 생성되었고 null 로 초기화 된 것을 볼 수 있습니다.

여기까지 보면 객체 배열이 만들어진 것 처럼 보입니다. 그러면 객체의 멤버변수에 값을 할당해보겠습니다.

        arrayObj[0].id = 10;
[실행값]
Exception in thread "main" java.lang.NullPointerException: Cannot assign field "id" because "arrayObj[0]" is null
	at com.kay.Main.main(Main.java:7)

오류 메시기가 발생했습니다. NullPointerException 포인터가 없습니다. 왜냐하면 arrayObj[0] 은 현재 null 값을 가리키고 있습니다. field인 id에 . 도트 연산자를 걸어서 사용하려고 했었죠? 이때 . 도트 연산자의 의미는 참조변수가 실제 객체를 찾아가서 객체의 멤버변수 값을 가져오는 것 입니다.

그런데 참조변수가 null 이니 일단 실제 객체(인스턴스)를 찾을 수 없습니다. 당연히 . 도트연산자도 먹히지 않습니다.

자바도 그렇고 C++도 그렇지만 . 도트연산자는 실제로 하는 행동이 과도하게 생략된 부분이 있습니다. 생략이 심하다는 것은 코딩의 타이핑수가 줄어든다는 이점도 있지만 정확한 내용을 알 수 없다는 단점도 있습니다.

new 키워드로 생성한 것은 객체를 담을 배열이었던 것 입니다. 실제 객체의 인스턴스를 생성하는 일은 별개의 메모리에서 이루어집니다.

이 부분이 객체 배열을 이해하는 핵심입니다. 처음에 배열을 동적할당 한 후 각 객체 인스턴스도 동적 메모리 할당을 합니다. new 키워드는 객체를 힙메모리에 할당합니다.

public class Main {
    public static void main(String[] args) {
        myObject[] arrayObj = new myObject[3];

//        사용할 수 없다
//        arrayObj[0].id = 10;

        arrayObj[0] = new myObject(101, "first  array, John");
        arrayObj[1] = new myObject(102, "second array, Mary");
        arrayObj[2] = new myObject(103, "third  array, Smith");

        for (int i = 0; i < arrayObj.length; i++) {
            System.out.println("arrayObj["+i+"] = " + arrayObj[i]);
        }
        
        arrayObj[0].showInfo();
        arrayObj[1].showInfo();
        arrayObj[2].showInfo();
    }
}
class myObject{
    int id;
    String description;

    myObject(){
    }
    public myObject(int id, String description) {
        this.id = id;
        this.description = description;
    }
    public void showInfo(){
        System.out.println("(id) : " + id);
        System.out.println("(description) : " + description);
    }
}
[실행값]
arrayObj[0] = com.kay.myObject@12edcd21
arrayObj[1] = com.kay.myObject@34c45dca
arrayObj[2] = com.kay.myObject@52cc8049
(id) : 101
(description) : first  array, John
(id) : 102
(description) : second array, Mary
(id) : 103
(description) : third  array, Smith

실행을 하면 객체 배열에 각 객체의 해시값이 할당된 것을 볼 수 있습니다. 이는 참조변수로 이제 . 도트연산자를 사용하여 멤버 변수를 찾아 갈 수 있습니다.

허나 도트 연산자로 개별 멤버에 접근하는 방식은 객체지향적이지 않으니까 여기서는 메소드를 사용해서 값을 출력합니다.

메소드를 만드는 일은 함수형 프로그래밍을 해온 사람에게는 매우 귀찮은 일처럼 다가옵니다. 한가지 팁은 인텔리제이 IDE의 자동 코드생성 기능을 활용하는 것 입니다. 표준 규격의 생성자, getter and setter, toString 등을 생성할 수 있습니다.

객체 배열의 구조

배열의 구조

객체 배열의 구조를 기존 배열 구조와 비교하면 좀 더 인사이트를 얻을 수 있습니다.

자바 배열 구조
자바 배열 구조

우선 자바 배열의 구조를 보겠습니다. 5개의 정수형 변수가 배열에 포함됩니다. 여기서도 new 키워드를 사용해서 변수 5개를 생성하고 myArray 에 할당합니다. int[] myArray 는 아직 선언만 하고 아무것도 없는 상황인데 여기서 new 키워드를 사용해서 메모리에 5개의 수를 할당하고 배열로 묶습니다.

myArray[0]의 주소만 알 수 있다면 4바이트(32bit)씩 이동해서 myArray[4] 까지 도달 할 수 있다는 것을 알 수 있습니다.

객체 배열 구조

아래 객체 배열의 경우 초기화가 null에서 시작합니다.

자바 객체 배열 구조
자바 객체 배열 구조

그리고 객체를 배열에 하나 할당했더니 어떻습니까? 객체의 참조 변수가 들어갔습니다. @12edc21 같은 암호같은 숫자는 해시값입니다.

JVM(자바가상머신)이 사용하기 때문에 왜 저런 번호를 사용하는지는 알 필요 없지만 실제 인스턴스가 저장된 메모리에 가서 데이터를 가져오기 위해 필요한 열쇠(key) 라고 생각하면 됩니다.

자바 배열의 구조와 무슨 차이가 있나요? 참조변수라는 단계를 한번 더 거쳐 가는 차이입니다.

또한 자바 배열이 new 키워드를 한번 사용해서 배열을 메모리에 할당하고 사용하는데 반하여, 자바 객체 배열은 배열을 만들때 new 키워드를 한번 객체를 만들 때 new 키워드를 한번 총 두번 사용하는 차이가 있습니다.

자바에서 new는 힙메모리의 사용을 의미한다고 했습니다. 상당히 중요한 개념입니다.

실상 프로그래머가 new 라고 메모리를 점유해놓고 삭제하지 않아도 GC(가비지 컬렉션)가 자동으로 메모리를 해제시킵니다. 그래서 C++ 보다 할일이 없습니다. 메모리 관리에 따라 매니지드(managed)와 언매니지드(unmanaged)를 나눌 정도로 상당히 중요한 차이입니다.

null 이란 여러가지 의미가 있지만 여기서는 참조가 없다 정도로 해석할 수 있습니다. 마찬가지로 생성자를 이용해서 인스턴스를 만들고 배열에 할당할 수 있습니다.

요약

자바 배열에는 기본 자료형을 사용하는 배열(Array)과 객체를 저장하는 객체 배열(Array of Objects)가 있습니다.

자바에서는 기본 단위가 객체로 들어가므로 객체 배열을 이해하는 것은 기초중의 기초라 할 수 있습니다. 따라서 시간을 들여 이해하고 넘어가는 것을 추천하며, 잘 이해가 안된다면 그림을 그려보세요.

자바의 참조변수는 C++보다 단순화되어 있기 때문에 이해가 쉬울수도 오히려 어려울 수도 있습니다.

여기까지 왔다면 충분히 이해할 수 있을 것입니다. 그럼 건투를 빕니다.

외부참조

자바 객체 배열(Array of Objects) 자바 강좌 6-3

How to Create Array of Objects in Java? – GeeksforGeeks

Leave a Comment