밤빵's 개발일지
[TIL]20241106 제네릭(Generic) 본문
제네릭은 코드의 타입 안정성과 재사용성을 높이는 중요한 개념이다. 자바에서 제네릭을 사용해본 경험이 있지만, 코틀린에서의 제네릭은 몇 가지 차이점과 함께 보다 직관적인 문법을 제공한다.
▶제네릭(Generic) 개념 이해
제네릭은 데이터의 타입을 일반화해 코드를 보다 유연하게 작성할 수 있는 방법으로 다양한 타입에 대해 하나의 코드 블록으로 처리할 수 있어 코드의 중복을 줄이고 유지보수성을 높인다. 제네릭은 주로 클래스나 함수에서 사용되며, 실행 시점이 아닌 컴파일 시점에 타입을 체크하여 타입 안정성을 확보할 수 있다.
▶제네릭 클래스 작성
제네릭 클래스를 선언할 때는 클래스 이름 뒤에 꺽쇠(<>) 안에 타입 매개변수를 지정한다.
class Box<T>(val content: T) {
fun getContent(): T {
return content
}
}
fun main() {
val intBox = Box(123)
val stringBox = Box("Hello, Kotlin")
println("IntBox contains: ${intBox.getContent()}")
println("StringBox contains: ${stringBox.getContent()}")
}
→ Box<T>는 제네릭 클래스로, T는 타입 매개변수이다. intBox와 stringBox는 각각 Int와 String 타입의 데이터를 저장하는 Box 객체이다. T는 사용자가 지정한 타입으로 대체되어 코드의 재사용성을 높이고, 컴파일 시점에 타입이 체크되어 타입 안정성을 보장한다.
▶제네릭 함수 작성
제네릭은 함수에서도 사용할 수 있다. 제네릭 함수를 작성할 때는 함수 이름 앞에 타입 매개변수를 꺽쇠(<>) 안에 정의한다.
fun <T> printItem(item: T) {
println("Item: $item")
}
fun main() {
printItem(42)
printItem("Hello, World!")
printItem(3.14)
}
→ printItem 함수는 타입 매개변수 T를 받아서 다양한 타입의 데이터를 출력할 수 있다. 이로 인해 함수는 Int, String, Double 등 어떤 타입이든 받을 수 있고, 호출 시점에 인자의 타입에 맞춰 T가 대체된다.
▶제네릭의 타입 제한 (Type Bound)
코틀린의 제네릭은 타입 제한(Type Bound)을 통해 특정 타입이나 타입 계층에 제약을 걸 수 있다. 이를 통해 함수나 클래스에서 사용할 타입의 범위를 제한하여 더욱 안전한 코드를 작성할 수 있다. 타입 제한을 적용하려면 T: SuperType과 같이 작성한다.
fun <T : Number> sumValues(a: T, b: T): Double {
return a.toDouble() + b.toDouble()
}
fun main() {
println(sumValues(10, 20))
println(sumValues(15.5, 4.5))
// println(sumValues("Hello", "World")) // 오류 발생: T는 Number 타입이어야 함
}
→ sumValues 함수는 타입 매개변수 T에 Number 타입의 제한을 두어 Int, Double, Float 등 Number의 서브 타입만 인자로 받을 수 있게 했다. 따라서 타입 안정성을 더욱 높일 수 있다.
▶코틀린의 제네릭과 자바의 제네릭 비교
자바에서도 제네릭을 사용하지만, 코틀린의 제네릭은 조금 더 직관적이고 간단한 문법을 제공한다. 코틀린에서는 제네릭 타입 매개변수에 공변성과 반공변성을 명시적으로 설정할 수 있으며, in과 out 키워드를 사용해 제네릭의 타입 변성을 제어한다. 자바에서는 ? extends와 ? super를 사용해 와일드카드로 변성을 처리하지만, 이는 가독성이 떨어지고 이해하기 어렵다.
▷코틀린
class Container<out T>(val item: T)
fun main() {
val stringContainer: Container<String> = Container("Kotlin")
val anyContainer: Container<Any> = stringContainer // 공변성(out) 덕분에 가능
}
▷자바
class Container<T> {
private T item;
public Container(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
public static void main(String[] args) {
Container<String> stringContainer = new Container<>("Java");
Container<? extends Object> anyContainer = stringContainer; // 와일드카드 사용
}
코틀린의 out 키워드는 자바의 ? extends와 비슷하지만 더 읽기 쉬운 문법을 제공한다.
제네릭은 타입 안정성을 높이고, 코드의 재사용성을 극대화할 수 있는 강력한 기능이다. 코틀린에서는 제네릭 클래스와 함수를 통해 다양한 타입을 다룰 수 있으며, 타입 제한과 변성을 통해 더 안전한 코드를 작성할 수 있다. 자바와 비교했을 때 코틀린의 제네릭은 간결하고 직관적인 문법을 제공하며, 이를 통해 가독성이 높은 코드를 작성할 수 있다.
'Kotlin' 카테고리의 다른 글
[TIL]20241108 Lazy (1) | 2024.11.08 |
---|---|
[TIL]20241107 실드클래스(Sealed Class) (1) | 2024.11.07 |
[TIL]20241105 Label & break/continue (1) | 2024.11.05 |
[TIL]20241104 Named Argument (1) | 2024.11.04 |
[TIL]20241103 Immutable Collection & Mutable Collection (6) | 2024.11.03 |