변성: 제네릭을 다룰 때 “타입 안전성”을 확보하기 위해 하위 타입 관계를 어떻게 적용할지를 결정하는 개념
예를 들어, Integer는 Number의 하위 타입인데, 이를 List<Integer>와 List<Number> 사이에 어떻게 적용할지 결정하는 것입니다.
변성 변경자: 코틀린에서 클래스나 인터페이스 선언 시, 타입 파라미터에 out(공변성) 또는 in (반공변성) 키워드로 변성 명시
공변성(out):
interface Producer<out T> { fun produce(): T }
반공변성(in):
interface Consumer<in T> { fun consume(item: T) }
선언 지점 변성을 사용하면 변성 변경자를 단 한 번만 표시하고 클래스를 쓰는 쪽에서는 변성에 대해 신경을 쓸 필요가 없으므로 코드가 더 간결해진다. 자바에서 사용자의 예상대로 작동하는 API를 만들기 위해 라이브러리 개발자는 항상 Function<? super T, ? extends R>처럼 와일드카드를 사용해야 한다. 자바 8 표준 라이브러리 소스코드를 살펴보면 Function 인터페이스를 사용하는 모든 위치에서 와일드카드를 볼 수 있다. 예를 들어, Stream.map 메소드는 다음과 같이 정의돼 있다.
public interface Stream {
<R> Stream <R> map(Function<? super T, ? extends R> mapper);
}
코틀린처럼 클래스 선언 지점에서 변성을 한 번만 지정하면 훨씬 더 간결하고 우아한 코드를 작성할 수 있다.
(아래는 AI로 생성한 개념들)
1. 생산(출력) vs 소비(입력) 이해하기
- 생산(출력, Return) 역할
인터페이스나 함수 내에서 T 타입의 값이 반환(return) 되는 경우를 말합니다.- 예시: fun produce(): T
이 메서드는 T 타입의 값을 "생산"합니다. - 핵심: 내부에서 T를 만들어서 밖으로 내보낸다.
- 예시: fun produce(): T
- 소비(입력, Parameter) 역할
인터페이스나 함수 내에서 T 타입의 값을 매개변수(parameter) 로 받는 경우를 말합니다.- 예시: fun consume(item: T)
이 메서드는 외부에서 받은 T 타입의 값을 "소비"합니다. - 핵심: 외부로부터 T를 받아들여 사용한다.
- 예시: fun consume(item: T)
2. 공변성 (out)
개념
- 코드 예시:
interface Producer<out T> { fun produce(): T }
- 여기서 T는 오직 반환(return) 용도로만 사용됩니다.
- 결과:
- Producer<Int>는 Producer<Number>의 하위 타입이 됩니다.
- 왜냐하면, Int는 Number의 한 종류이므로, 어떤 곳에서 Producer<Number>가 필요할 때, Producer<Int>를 안전하게 사용할 수 있기 때문입니다.
장점
- 유연성:
예를 들어, 함수에서 Producer<Number>를 요구하면, 정수만 생산하는 Producer<Int>도 넣을 수 있습니다. - 타입 안전성:
생산자에서는 값을 단순히 반환만 하므로, 하위 타입으로 대체되어도 문제 없이 작동합니다.
3. 반공변성 (in)
개념
- 코드 예시:
interface Consumer<in T> { fun consume(item: T) }
- 여기서 T는 오직 입력(parameter) 용도로만 사용됩니다.
- 결과:
- Consumer<Number>는 Consumer<Int>의 하위 타입이 됩니다.
- 왜냐하면, Number를 소비하는 Consumer는 Int도 문제없이 처리할 수 있기 때문입니다. (Int는 Number의 한 종류이므로)
장점
- 유연성:
예를 들어, 어떤 함수가 Consumer<Int>를 요구할 때, Number를 받아 처리할 수 있는 Consumer<Number>를 넣어도 안전합니다. - 타입 안전성:
소비자에서는 단순히 외부에서 값을 받아들이기만 하므로, 상위 타입을 사용하는 것이 안전합니다.
반응형
'Kotlin' 카테고리의 다른 글
[Kotlin in Action] 10.1 annotation 선언과 적용 (0) | 2025.04.03 |
---|---|
[Kotlin] 스타 프로젝션(*)과 Any의 차이 (0) | 2025.04.03 |
[Kotlin in Action] 9.3 변성: 제네릭과 하위 타입 (0) | 2025.04.02 |
[Kotlin in Action] 9.2 실행 시 제네릭스의 동작: 소거된 타입 파라미터와 실체화된 타입 파라미터 (0) | 2025.04.02 |
[Kotlin in Action] 9.1 제네릭 타입 파라미터 (0) | 2025.04.02 |
댓글