프로그래밍Kotlin 개발자

Kotlin에서 'inline' 키워드를 클래스(value class/inline class)에 적용하는 방법은 무엇인가요? 어떤 제한이 있으며, 이러한 클래스가 바이트코드 수준에서 어떻게 작동하고, 언제, 왜 사용하는 것이 좋나요? 예제를 제시하고 전형적인 복잡성을 설명하세요.

Hintsage AI 어시스턴트로 면접 통과

답변

Kotlin의 inline class (Kotlin 1.5부터는 "value class"라는 용어),는 최소한의 오버헤드로 타입의 래퍼를 생성할 수 있게 해줍니다. 컴파일 시 이러한 클래스는 내부 값(value)으로 대체되어 객체 생성에 대한 오버헤드를 피합니다.

제한사항 및 특징:

  • primary constructor에 단 하나의 속성만 가질 수 있습니다.
  • 참조 동등성에 대한 참조를 저장할 수 없습니다 (===가 일반적으로 작동하지 않음).
  • Value class는 상속 클래스가 될 수 없으며 자신의 value를 제외한 상태를 가질 수 없습니다.
  • 모든 제네릭 타입 및 플랫폼 API가 inline/value class와 boxing 없이 작업할 수 있는 것은 아닙니다.
  • Value class는 init 블록과 value 외의 필드, 최소한의 함수만 가질 수 있습니다.

예제:

@JvmInline value class UserId(val value: String) fun getUser(id: UserId) { println("Loading user with id: ${id.value}") } val id = UserId("XYZ") getUser(id) // 내부적으로는 단순히 String으로 작업합니다!

사용할 때:

  • 식별자 및 특별한 값을 위한 타입 안전성을 보장함.
  • 유사한 래퍼가 수백만 개일 때 성능 향상 (객체가 생성되지 않음).

속임수 질문

value class를 상속하거나 인터페이스/추상 클래스 계층에서 사용할 수 있나요?

답변: 아니요, value class는 다른 클래스(인터페이스 제외)를 상속할 수 없으며, 상속을 위해 열 수 없고, init 블록 및 기타 비정적 필드를 허용하지 않습니다. 유일한 가능한 방법은 인터페이스를 구현하는 것입니다.

예제:

interface Validatable { fun isValid(): Boolean } @JvmInline value class Email(val raw: String) : Validatable { override fun isValid() = raw.contains("@") }

주제에 대한 지식 부족으로 인한 실제 오류 사례


이야기

Android 애플리케이션은 Parcelable의 매개변수에 value class를 추가한 후 스타트 시간이 급격히 증가했습니다: 잘못된 @Parcelizevalue class가 직렬화의 모든 단계에서 boxing/unboxing을 초래하여 inline의 장점을 무너뜨렸습니다.


이야기

마이크로서비스는 타입 안전성을 위해 UserId와 ProductId에 대해 value class를 적극적으로 사용하기 시작했지만, 많은 곳에서 제네릭 함수가 반사(reflection)를 요구하여 "래퍼"와 함께 작동하지 않았습니다. 유닛 테스트가 의외로 실패하기 시작했고, ClassCastException이 발생했습니다.


이야기

Java에서 마이그레이션된 코드는 최적화를 위해 내부 도메인 클래스를 value class로 대체하기 시작했지만, nullable 필드로 사용함에 따라 예상치 못한 null pointer exception이 발생했습니다. value class는 외부 값이 null일 때만 null이 될 수 있기 때문에, 이는 기존의 불변성을 깨뜨렸습니다.