CodeGym /행동 /JAVA 25 SELF /record와 class의 차이점, record의 제한 사항

record와 class의 차이점, record의 제한 사항

JAVA 25 SELF
레벨 22, 레슨 4
사용 가능

1. record와 class 비교: 핵심 차이점은 무엇인가?

Java에는 데이터 타입을 정의하는 두 가지 주요 방법이 있습니다: 일반 클래스(class)와 record 클래스(record)입니다. 겉보기에는 둘 다 데이터를 저장하고 처리할 수 있습니다. 하지만 조금만 더 깊이 들여다보면 생각보다 차이가 많습니다!

차이점 표: class vs record

특징 일반 클래스 (class) record 클래스 (record)
가변성 제한 없음: 필드를 final로 하거나 아니어도 됨 불변: 모든 필드가 final
상속 상속 가능(extends), 기본적으로 final 아님 항상 final, 슈퍼클래스가 될 수 없음
필드 제한 없음: static/인스턴스, final/비-final, 어떤 타입이든 record 컴포넌트만(private final), 추가로 static 필드 가능
Getter/Setter 직접 작성(또는 Lombok으로 생성) Getter는 자동 생성(필드명이 메서드명), Setter는 없음
equals/hashCode/toString 보통 수동 구현/생성(equals, hashCode, toString) 모든 컴포넌트를 기준으로 자동 생성
생성자 제한 없음, 몇 개든 가능 모든 컴포넌트를 받는 기본 생성자 하나, compact constructor 추가 가능
인터페이스 구현 가능 구현 가능
추가 메서드 제한 없음 추가 가능하나 메서드만(필드는 불가)
컬렉션에서의 사용 가능하지만 equals/hashCode를 올바르게 구현해야 함 키/값에 이상적, 이미 구현되어 있음

이해를 돕는 예

일반 클래스:


public class Person {
    private final String name;
    private final int age;

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

    public String getName() { return name; }
    public int getAge() { return age; }

    @Override
    public boolean equals(Object o) { /* ... */ }
    @Override
    public int hashCode() { /* ... */ }
    @Override
    public String toString() { /* ... */ }
}

record 클래스:


public record Person(String name, int age) { }

끝! 코드 한 줄이면 동일한(더 나은) 결과를 얻습니다. 중요한 구현을 빠뜨릴 위험도 없습니다.

2. record 클래스의 제한 사항

record 클래스는 단순한 ‘짧은 문법’이 아니라 자체 규칙이 엄격한 별도의 개념입니다. 자세히 살펴보겠습니다.

record는 항상 final

record 클래스는 정의상 항상 final입니다. 즉, record의 하위 클래스를 만들 수 없습니다:


public record Point(int x, int y) { }

// public class ColoredPoint extends Point { } // 컴파일 오류!

동작을 확장해야 한다면 일반 클래스를 사용하거나 컴포지션을 사용하세요(record를 클래스에 포함).

record는 슈퍼클래스가 될 수 없음

record 클래스는 다른 클래스의 부모가 될 수 없으며, 항상 final입니다. 이는 논리적입니다. 만약 가능했다면 누군가 가변 필드를 추가할 수 있고, 그러면 ‘불변 데이터’라는 개념이 무너집니다.

오직 final 필드(컴포넌트)만

record의 모든 컴포넌트는 헤더에서 선언되며 기본적으로 private final입니다. record 본문에 인스턴스 필드를 추가할 수 없습니다:


public record User(String login, String email) {
    // int counter; // 오류! 인스턴스 필드를 추가할 수 없음
    static int totalUsers = 0; // 가능, static 필드
}

Setter 없음

record 클래스에는 컴포넌트에 대한 setter가 없습니다. setX(int x) 같은 메서드를 추가하더라도 무의미합니다. 객체 생성 이후에는 필드 값을 변경할 수 없기 때문입니다.


public record Point(int x, int y) {
    // public void setX(int x) { this.x = x; } // 오류: final 필드는 변경할 수 없음
}

기본(무인자) 생성자 없음

record 클래스에는 항상 모든 컴포넌트 값을 받는 기본 생성자만 있습니다. 모든 데이터를 지정하지 않고 record를 생성할 수는 없습니다:


Point p = new Point(1, 2);  // 정상
// Point p = new Point();   // 오류: 매개변수 없는 생성자가 없음

비정적 초기화자 없음

record 클래스에는 메서드 바깥의 중괄호 블록으로 작성하는 비정적 초기화자를 둘 수 없습니다:


public record User(String login) {
    // { /* ... */ } // 오류: 비정적 초기화자는 금지됨
}

상속 관련 제한

record 클래스는 다른 클래스를 명시적으로 상속할 수 없습니다(java.lang.Record는 모든 record의 베이스 클래스로 숨겨져 있음). 하지만 인터페이스 구현은 가능합니다!


public interface Printable {
    void print();
}

public record Book(String title) implements Printable {
    @Override
    public void print() {
        System.out.println("책을 출력합니다: " + title);
    }
}

복잡한 비즈니스 로직에는 부적합

record는 ‘데이터’ 중심이며 ‘행동’ 중심이 아닙니다. 객체에 복잡한 로직, 가변 상태, ‘생명 주기’ 또는 많은 의존성이 있다면 record는 도움이 되지 않습니다. 일반 클래스를 사용하세요.

3. record 클래스를 언제 사용해야 할까요?

  • DTO (Data Transfer Object): 애플리케이션 계층, 서비스, 마이크로서비스 또는 REST 컨트롤러 간에 불변 데이터를 전달할 때(예: JSON 응답).
  • Value Object: 오직 값으로만 정의되는 객체.
  • 컬렉션의 키와 값: equals와 hashCode의 올바른 구현이 중요한 경우(예: HashMap이나 Set에서 사용).
  • 계산 결과: 메서드에서 여러 값을 한 번에 반환해야 할 때(예: record Pair<T, U>(T first, U second)).

예: REST 컨트롤러용 DTO


public record UserDto(String login, String email) { }

이제 컨트롤러에서 안심하고 이 타입의 객체를 반환할 수 있습니다. 누군가가 필드를 바꿀 걱정이 없습니다.

예: HashMap의 키


public record Point(int x, int y) { }

Map<Point, String> pointNames = new HashMap<>();
pointNames.put(new Point(1, 2), "A");
pointNames.put(new Point(3, 4), "B");

// 모두 정상 동작: equals와 hashCode가 이미 구현되어 있음!

4. record 클래스를 사용하면 안 되는 경우

  • 가변 상태: 객체 생성 후 하나라도 바뀌어야 하는 필드가 있는 경우.
  • 복잡한 로직: 객체에 복잡한 행위, 많은 메서드, 가변 상태의 중첩 객체가 있는 경우.
  • 상속: 클래스 계층, 추상 베이스 클래스, 메서드 오버라이딩이 필요한 경우.
  • 비즈니스 로직의 엔티티: 예를 들어 데이터베이스에 저장되고 고유 식별자를 가지는 객체.

예: 일반 클래스가 필요한 경우


public class Account {
    private String id;
    private int balance;

    public Account(String id, int balance) {
        this.id = id;
        this.balance = balance;
    }

    public void deposit(int amount) { balance += amount; }
    public void withdraw(int amount) { balance -= amount; }
    // getters, setters, equals, hashCode, toString...
}

이 예제는 객체의 상태가 변경됨이 명확합니다 — record는 적합하지 않습니다.

5. 실전 예시: record와 class 중 선택하기

예제 1: record — 최적의 선택


public record Rectangle(int width, int height) {
    public int area() {
        return width * height;
    }
}
  • 사각형은 너비와 높이로만 정의됩니다.
  • 생성 후 값을 변경할 필요가 없습니다.
  • 유용한 메서드 area()를 추가할 수 있습니다.
  • 나머지는 Java가 알아서 처리합니다.

예제 2: class — 더 좋은 선택


public class MutableRectangle {
    private int width;
    private int height;

    public MutableRectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public void setWidth(int width) { this.width = width; }
    public void setHeight(int height) { this.height = height; }

    public int area() { return width * height; }
}

생성 후 사각형의 크기를 바꿔야 하나요? 일반 클래스를 사용하세요.

6. record 클래스를 사용할 때 흔한 실수

오류 №1: 인스턴스 필드를 추가하려는 시도.
record 클래스는 컴포넌트 목록 밖에서 인스턴스 필드를 선언할 수 없습니다. 시도하면 컴파일러가 오류를 발생시킵니다. 예:


public record City(String name) {
    // int population; // 오류!
}

오류 №2: setter를 추가하려는 욕구.
record는 컴포넌트에 대한 setter를 지원하지 않습니다. 생성 이후 필드 값을 바꾸려는 모든 시도는 컴파일 오류입니다.

오류 №3: record를 상속하거나 record로부터 상속하려는 시도.
record는 항상 final입니다. record에서 상속할 수 없고, record가 다른 클래스를 상속할 수도 없습니다(숨겨진 java.lang.Record 제외).

오류 №4: mutable 객체에 record 사용.
생성 후 객체 상태를 바꿀 계획이라면 — record는 맞지 않습니다! 일반 클래스를 사용하세요.

오류 №5: 생성자 제약을 잊는 경우.
record 클래스에는 모든 컴포넌트 값을 받는 생성자가 반드시 있어야 합니다. 무인자 생성자는 없습니다!

1
과제
JAVA 25 SELF, 레벨 22, 레슨 4
잠금
중첩된 주소를 가진 회사 카드 🏢
중첩된 주소를 가진 회사 카드 🏢
1
과제
JAVA 25 SELF, 레벨 22, 레슨 4
잠금
지도에서 좌표 일치 확인 🗺️
지도에서 좌표 일치 확인 🗺️
1
과제
JAVA 25 SELF, 레벨 22, 레슨 4
잠금
문서 내용 출력 📄
문서 내용 출력 📄
1
과제
JAVA 25 SELF, 레벨 22, 레슨 4
잠금
변경 가능한 사용자 프로필과 불변 프로필 비교 🧑‍🤝‍🧑
변경 가능한 사용자 프로필과 불변 프로필 비교 🧑‍🤝‍🧑
1
설문조사/퀴즈
Record 클래스, 레벨 22, 레슨 4
사용 불가능
Record 클래스
Record 클래스
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION