목차
들어가기 전에
자바 14부터 코틀린의 Data 클래스와 유사한 Record라는 클래스가 추가되어 자바 16에서 정식으로 지원되기 시작했다. 그동안 자바에서 DTO 등의 클래스를 만들 때는 Lombok의 도움을 받아 @Data
어노테이션을 붙이는 경우가 많았지만 Record 클래스가 추가되어 이러한 필요성이 줄어들게 되었다.
하지만 자바의 Record 클래스와 코틀린의 Data 클래스는 비슷하지만 다른 점이 있다. 이에 대해 정리해본다.
Record 클래스의 기본 구조와 사용법
Record 클래스는 아래와 같은 구조로 선언된다.
public record Member(
String account,
String name,
int age
) {
...
}
클래스 명 뒤에 소괄호로 메소드의 파라미터를 지정하듯이 클래스의 필드들을 정의한다. 이 때 필드 앞에 접근 지정자는 입력할 수 없다.
Record 클래스의 선언 방식은 코틀린 클래스의 선언 방식과 굉장히 유사한 것을 볼 수 있다. 코틀린 클래스와 마찬가지로 Record 클래스 선언의 소괄호 내부에 있는 필드들은 모두 생성자의 파라미터가 된다. 다만 클래스 내에 다른 내용이 없으면 중괄호를 생략할 수 있는 코틀린 클래스와는 달리 Record 클래스는 클래스 내에 다른 내용이 없더라도 중괄호가 반드시 있어야 한다.
Record 클래스의 프로퍼티를 가져다 쓸 때는 일반적인 클래스의 Getter 형식인 getXXX()
가 아니라 필드의 이름 그대로 XXX()
를 사용한다. 위의 Member 객체에서 name
을 조회하고 싶다면 member.name()
과 같이 사용하면 된다.
Record 클래스는 Data 클래스와 마찬가지로 toString()
, equals()
, hashCode()
가 정의되어 있다.
Record 클래스의 특징
그럼 이제 자바 Record 클래스와 코틀린 Data 클래스의 특징을 비교해보자.
Record 클래스는 모든 프로퍼티가 final
이다.
프로퍼티를 선언할 때 val
과 var
모두 사용할 수 있는 코틀린의 Data 클래스와 달리 자바의 Record 클래스는 모든 필드가 묵시적으로 final
로 선언된다.
모든 필드가 final
이니, 당연히 Setter도 존재하지 않고 객체의 불변성이 어느정도 보장된다. Record 클래스를 선언할 때 필드에 final
이 붙지 않았다고 직접 Setter를 만들거나 상태값을 변경하는 메소드를 만들려고 하면 컴파일 에러가 발생한다.
물론 Record 클래스의 필드에 객체가 있다면 완벽한 불변성이 보장되지 않을 수 있다. 원시 타입이 아닌 모든 객체는 참조 주소를 전달하는 Call by Reference로 동작하기 때문에 객체를 단순히 조회한 후 상태값을 바꾸면 원본 객체의 상태값이 바뀌게 된다. 이 경우에는 필드로 포함된 객체도 불변 객체여야 불변성을 보장할 수 있다.
Record 클래스는 상속이 불가능하다
코틀린의 Data 클래스는 다른 클래스를 상속받을 수 있고, (권장되는 것도 아니고 약간의 편법을 사용해야하긴 하지만) 다른 클래스에서 상속받을 수 있는 것과 달리 Record 클래스는 다른 클래스를 상속받을 수 없으며, 다른 클래스에서 Record 클래스를 상속받을 수도 없다.
Record 클래스가 다른 클래스를 상속받을 수 없는 이유는 사실 Record라는 추상 클래스를 상속받아서 구현되기 때문이다. 클래스는 하나의 클래스로부터만 상속받을 수 있는데 이미 상속을 받고 있으니 다른 클래스를 상속받을 수 없는 것이다.
Record 클래스는 copy()
메소드가 없다
그 외에도 원칙적으로 모든 것이 final
인 Record 클래스의 특성 상 copy()
는 굳이 지원하지 않는다.
마치며
자바의 Record 클래스는 코틀린의 Data 클래스와 유사하지만 조금 더 안전한 사용을 위해서인지 여러 제약을 두었다는 점이 흥미로웠다. 코틀린에서는 val
의 사용을 권장하면서도 var
도 사용할 수 있던 것과 달리 아예 final
로 제한을 해버렸다는 점에서 불변성에 초점을 둔게 아닐까 싶다.
실제로는 추상 클래스를 상속받아 구현되고 있다는 점도 꽤나 재밌는 점이다. record
라는 키워드가 추가되어 언어 차원에서 추가된 기능인가 했는데 사실은 상속받아서 구현되고 있었다는게 오묘한 느낌이다.
참조링크
'Programming Language > Kotlin & Java' 카테고리의 다른 글
[Kotlin/Java] JUnit을 사용한 단위 테스트에서 System.in을 사용하는 콘솔 입력 로직 테스트하기 (0) | 2023.12.07 |
---|---|
[Java] UnmodifiableList는 진짜 불변 리스트가 아니다 (0) | 2023.08.15 |
[Kotlin] 확장 함수와 람다를 사용해서 중복 코드를 제거해보자! (0) | 2023.05.08 |
[Java/Kotlin] 필드(Field)와 프로퍼티(Property)는 무슨 차이가 있을까? (0) | 2023.05.02 |
[Kotlin] Java와 Kotlin, 그리고 Lombok (0) | 2023.04.21 |
댓글