[Kotlin] Any, *, Generic의 공통점과 차이점
🍎 Kotlin 환경에서 Type에 관련해 제공되는 기능 Any, *, Generic을 이해하기 위해 정리한 글
🍎 공통점
- Any, *, Generic은 Kotlin 환경에서 특정 타입에 구애받지 않고 다양한 타입에 대해 작업할 수 있는 유연성을 제공합니다.
🍎 차이점
Any, *, Generic은 모두 타입 시스템에서 유연성을 제공하는 역할을 하지만, 각각의 사용 목적과 상황이 다릅니다. 각 요소의 특징을 살펴보면 어떤 상황에서 어떤 타입을 사용하는 것이 적절한지 더 잘 이해할 수 있을 것입니다.
🍏 Any
- Any는 모든 타입의 최상위 타입입니다. 모든 Kotlin 타입은 Any 타입을 상속합니다.
- Any는 Java의 Object와 유사한 역할을 수행합니다.
- 모든 값이 Any Type으로 취급되기 때문에, 어떤 종류의 값이든 저장하고 전달할 수 있습니다. 하지만 이는 타입 안전성을 포기하는 것을 의미합니다.
val anyValue: Any = 42
🍏 * (Star Projection)
- Star Projection은 주로 Generic Type을 다룰 때 사용되며 WildCard Type을 표현합니다.
- Generic Type을 선언할 때 특정 타입 인자를 알지 못할 때 사용할 수 있습니다.
- 타입 안전성의 측면에서 Star Projection은 쓰기 작업보다 읽기 작업에 더 적합합니다.
- Star Projection이 읽기 작업에 더 적합한 이유는 읽어들일 때 Type에 대한 정보가 없어도 문제가 없기 때문입니다. 반면 쓰기 작업에 사용하게 된다면리스트에 추가할 때, 구체적인 타입이 명시되지 않기 때문에 어떤 타입의 객체가 추가될지 알 수 없어 컴파일러가 이를 막습니다.
fun printList(list: List<*>) {
// 읽기 작업
for (item in list) {
println(item)
}
// 쓰기 작업은 불가능
// list.add("New Item") // 컴파일 오류
}
🍏 Generic T
- 제네릭 타입 매개변수 ‘T’는 개별적인 제네릭 타입을 나타냅니다. 사용할 때마다 구체적인 타입으로 대체됩니다.
- 제네릭을 사용하면 타입 안전성을 유지하면서 코드의 재사용성을 높일 수 있습니다.
- 컴파일러가 타입을 실제로 채워서 타입 안정성을 유지하도록 도와줍니다. 제네릭은 컴파일 시점에 타입 체크를 하여 프로그램의 타입 안전성을 보장하는 데 사용됩니다.
// 제네릭 클래스 정의
class Box<T>(var value: T) {
fun getValue(): T {
return value
}
fun setValue(newValue: T) {
value = newValue
}
}
fun main() {
// Int 타입을 저장하는 Box
val intBox = Box(123)
println("Int Box value: ${intBox.getValue()}") // 출력: Int Box value: 123
// String 타입을 저장하는 Box
val stringBox = Box("Hello, Kotlin!")
println("String Box value: ${stringBox.getValue()}") // 출력: String Box value: Hello, Kotlin!
// 타입을 변경할 수 있습니다.
stringBox.setValue("New Value")
println("Updated String Box value: ${stringBox.getValue()}") // 출력: Updated String Box value: New Value
// 타입 안전성을 보장하기 때문에 다음과 같은 코드는 컴파일 에러를 발생시킵니다.
// intBox.setValue("Hello") // 컴파일 에러: Type mismatch: inferred type is String but Int was expected
}
- Any, *(Star Projection), Generic에 대해 알아본 결과 Star Projection은 Type을 알 수 없을 때 Any, Generic에 사용될 수 있다는 것을 알 수 있었습니다.
❓ 그렇다면 어느 상황에서 Any, Generic을 사용해야 할까요?
- Any와 Generic의 큰 차이는 Type 안전성입니다. 타입을 다룰 때 안전성이 존재하는 Generic만을 사용하는 것이 좋다고 생각할 수도 있겠지만 Any도 필요합니다.
- Any는 모든 타입을 다뤄야하는 상황에서 필요하며 타입 안전성을 포기하고 Trade-off를 진행하는 것입니다. 즉, 타입이 다양하거나 특정 타입이 명확하지 않은 상황에서 유용하게 사용될 수 있습니다.