개발
home
🍀

[다형성] Kotlin의 Any, * 그리고 Java의 ?

Created
2024/12/19
Tags
Generic
Kotlin
Java
2024-12-19 @이영훈

들어가며

제네릭 타입을 다루다 보면 Kotlin과 Java에서 비슷하지만 다른 문법을 마주하게 됩니다.
대표적으로 KotlinAny*, 그리고 Java?이 있습니다.
저는 Any?, *의 차이를 이해하는 것이 중요했습니다.

1. Kotlin Any

의미: 모든 non-null 타입의 최상위 타입 (Java의 Object와 비슷)
Any?를 사용하면 nullable 타입까지 포함할 수 있습니다.
Collection에서 꺼냈을 때는 Any 또는 Any? 타입입니다.
예시:
val myList1: List<Any> = listOf("a", 1, true) // ⭕️ myList1[0] // 타입: Any val myList2: List<Any> = listOf("a", 1, true, null) // ❌ 컴파일 에러. null을 입력할 수 없음 val myList3: List<Any?> = listOf("a", "b", null) // ⭕️ Any?이기 때문에 null을 입력할 수 있음 myList[0] // 타입: Any?
Kotlin
복사

2. Kotlin * (Star Projection)

의미: 타입 인자를 명시하지 않고, 정확한 타입을 모른다는 표시 (Java의 ?와 비슷)
null을 포함한 모든 타입을 포함합니다
Collection에서 꺼냈을 때는 Any? 타입입니다.
예시:
val myList: List<*> = listOf("a", 1, true, null) // ⭕️ null 타입을 입력할 수 있음 myList[0] // 타입: Any?
Kotlin
복사

중요한 차이점

다형성 관점에서 List<*>는 "타입을 알 수 없으나, 최소한 읽을 수 있는(Read-only) 리스트"로 간주할 수 있습니다.
MutableList<Any>는 원소를 추가할 수 있지만 MutableList<*>은 원소를 추가할 수 없습니다.
예시:
val myList2: MutableList<Any> = mutableListOf("a", 1, 2L) myList2.add(true) // ⭕️ val myList3: MutableList<*> = mutableListOf("a", 1, 2L) myList3.add(2) // ❌ 컴파일 에러
Kotlin
복사

3. Java ? (Wildcard)

의미: 타입 매개변수를 알 수 없거나 특정 상하한 경계를 가진 제네릭
Collection에서 꺼냈을 때 Object 타입
예시:
void printAll(List<?> list) { // 어떤 타입의 리스트인지 정확히 모름 for (Object elem : list) { System.out.println(elem); } }
Java
복사
? extends T? super T를 통해 상하한 경계를 지정할 수 있습니다.
Kotlin에서는 이를 out(covariance)와 in(contravariance) 키워드로 대체합니다.