제네릭(generic)
자료형의 객체들을 다루는 메서드나 클래스에서 컴파일 시간에 자료형을 검사해 적당한 자료형을 선택할 수 있도록 하기 위해 사용
<>
) 사이에 형식 매개변수를 사용해 선언class Box<T>(t: T) { // 제네릭을 사용해 형식 매개변수를 받아 name에 저장
var name = t
}
fun main() {
val box1: Box<Int> = Box<Int>(1)
val box2: Box<String> = Box<String>("Hello")
println(box1.name) // 1
println(box2.name) // Hello
}
형식 매개변수의 이름
형색 매개변수 이름 | 의미 |
---|---|
E | 요소(element) |
K | 키(key) |
N | 숫자(number) |
T | 형식(type) |
V | 값(value) |
S, U, V etc. | 두 번째, 세 번째, 네 번째 형식(2nd, 3rd, 4th types) |
자료형의 추론
val box3 = Box(1) // Box<Int>로 유추
val box4 = Box("Hello") // Box<String>로 유추
제네릭 클래스
형식 매개변수를 한 개 이상 받는 클래스
class MyClass<T> { // 한 개의 형식 매개변수를 가지는 클래스
fun myMethod(a: T) { // 메서드의 매개변수 자료형에 사용됨
...
}
}
프로퍼티에 지정하는 경우
class MyClass<T> (val myProp: T) { } // 주 생성자의 프로퍼티
class MyClass<T> {
val myProp: T // 프로퍼티
constructor(myProp: T) { // 부 생성자 이용
this.myProp = myProp
}
}
var a = MyClass<Int>(12) // 주 생성자 myProp에는 12가 할당되며 정수형으로 결정됨
println(a.myProp) // 12
println(a.javaClass) // MyClass
제네릭 클래스의 자료형 변환
open class Parent
class Child: Parent()
class Cup<T>
fun main() {
val obj1: Parent = Child() // Parent 형식의 obj1은 Child로 형 변환될 수 있음
val obj2: Child = Parent() // error! 하위 형식인 Child의 객체 obj2는 Parent로 변환되지 않음
val obj3: Cup<Parent> = Cup<Child>() // error! 자료형 형식이 일치하지 음
val obj4: Cup<Child> = Cup<Parent>() // error! 자료형 형식이 일치하지 음
val obj5 = Cup<Child>() // obj5는 Cup<Child> 형식이 됨
val obj6: Cup<Child> = obj5 // 형식이 일치하므로 ok
}
형식 매개변수의 null 제어
class GenericNull<T> { // 기본적으로 null이 허용되는 형식 매개변수
fun EqualityFunc(arg1: T, arg2: T) {
println(arg1?.equals(arg2))
}
}
fun main(args: Array<String>) {
val obj = GenericNull<String>() // non-null로 선언됨
obj.EqualityFunc("Hello", "World") // null이 허용되지 않음
val obj2 = GenericNull<Int?>() // null이 가능한 형식으로 선언됨
obj2.EqualityFunc(null, 10) // null 사용
}
<T: Any>