2 분 소요

자바(Java) 참조 타입(reference type)은 변수에 객체의 주소값을 저장해 두고, 실제 데이터는 힙(Heap) 메모리에 두는 방식입니다. 기본 타입이 “값 자체”를 다루는 것과 달리, 참조 타입은 객체 지향 프로그래밍(OOP)에서 필수적인 객체(클래스·배열·인터페이스·열거형)를 다루게 해 줍니다. 이 글에서는 참조 타입의 개념부터 사용 예시·주의점까지 초보자도 이해할 수 있도록 상세히 설명드리겠습니다.


참조 타입이란?

참조 타입은 다음과 같은 특징을 가집니다.

  • 객체 주소 저장: 변수에는 객체가 위치한 메모리 주소만 저장됩니다.
  • 힙 메모리 사용: 실제 객체(데이터)는 에 생성되고, 스택에는 주소가 저장됩니다.
  • 기본값은 null: 초기화하지 않으면 null(값 없음)을 가집니다.
  • 크기 JVM 의존: 32 bit JVM에서는 4 byte, 64 bit JVM에서는 8 byte 등 구현에 따라 주소 크기가 달라집니다.

용어

힙(Heap) – 동적으로 생성된 객체를 저장하는 영역. 스택(Stack) – 메서드 호출과 지역 변수를 저장하는 영역.


참조 타입의 종류

클래스(Class)

클래스를 기반으로 만들어진 객체를 가리킵니다.

String greeting = "Hello, Java!";   // String 객체를 참조
Scanner sc = new Scanner(System.in); // Scanner 객체 참조
  • 사용자 정의 클래스도 동일하게 참조 타입입니다.

배열(Array)

동일 타입 데이터를 연속적으로 담는 자료구조이며, 사실상 “배열 객체”로 취급됩니다.

int[] numbers = {1, 2, 3, 4};

인터페이스(Interface)

인터페이스를 구현한 객체를 참조합니다. 다형성(Polymorphism)을 구현할 때 필수입니다.

List<String> list = new ArrayList<>();

열거형(Enum)

상수 집합을 표현하는 타입으로, 내부적으로도 참조 타입입니다.

enum Day { MONDAY, TUESDAY, WEDNESDAY }
Day today = Day.MONDAY;

기본 타입 vs. 참조 타입

구분 기본 타입 (Primitive) 참조 타입 (Reference)
저장 값 자체 객체 주소값
기본값 0, false null
위치 스택 주소: 스택 / 데이터: 힙
예시 int, double, boolean String, 배열, 사용자 정의 클래스
사용 목적 단순 연산·메모리 절약 객체·복합 구조 처리

참조 타입 활용 예제

클래스 객체 참조

class Person {
    String name;
    int age;
}

public class ReferenceExample {
    public static void main(String[] args) {
        Person person = new Person(); // 객체 생성
        person.name = "Alice";
        person.age  = 30;
        System.out.println(person.name); // Alice
        System.out.println(person.age);  // 30
    }
}

배열 객체 참조

public class ArrayExample {
    public static void main(String[] args) {
        int[] scores = {90, 85, 78};
        for (int s : scores) System.out.println(s);
    }
}

String 객체 비교

String str1 = "Hello";
String str2 = new String("Hello");
System.out.println(str1 == str2);      // false (주소 비교)
System.out.println(str1.equals(str2)); // true  (값 비교)

*==주소를, equals()내용을 비교*한다는 점을 꼭 기억하세요.


참조 타입 사용 시 주의사항

  1. NullPointerException(NPE)

    초기화되지 않은 참조(null)에 접근하면 런타임 오류가 발생합니다.

    해결: Optional, null 체크(Objects.requireNonNull) 활용.

  2. 메모리 누수

    더는 사용하지 않는 객체를 참조 변수에 남겨 두면 가비지 컬렉터가 회수하지 못해 메모리 누수가 생길 수 있습니다.

  3. 얕은 복사(shallow copy) vs. 깊은 복사(deep copy)

    참조를 그대로 복사하면 원본 데이터가 같이 변경될 위험이 있으므로, 필요하다면 deep copy 로직을 구현해야 합니다.


질문 정리

  1. 참조 타입 변수의 기본값이 왜 null인가요?

    객체 주소가 아직 할당되지 않았음을 명확히 나타내어, 의도치 않은 접근을 방지하기 위함입니다.

  2. String은 왜 특별한가요?

    String불변(immutable) 객체로, 값이 바뀔 때마다 새 인스턴스를 생성합니다. 문자열 결합이 잦다면 StringBuilder를 사용해 성능을 개선할 수 있습니다.

  3. 배열 크기를 동적으로 변경하려면?

    자바 배열은 고정 크기입니다. 크기가 변할 가능성이 있다면 ArrayList, LinkedList 같은 컬렉션 프레임워크를 사용하세요.

  4. 인터페이스 타입으로 변수를 선언하는 이유는?

    구현 클래스를 바꿔도 코드 수정이 최소화되고, 테스트·유지보수성이 좋아지기 때문입니다.

  5. 열거형도 객체인가요?

    네, enum 상수 각각이 Singleton 객체처럼 동작하며, 메서드·필드를 가질 수 있어 코드 가독성과 타입 안전성을 높입니다.

카테고리:

업데이트:

댓글남기기