Do it! 코틀린 프로그래밍 [셋째마당, 코틀린 표준 라이브러리의 활용] 학습
- 제네릭(Generic) 은 클래스 내부에서 사용할 자료형을 나중에 인스턴스를 생성할 때 확정
- 자료형의 객체들을 다루는 메서드나 클래스에서 컴파일 시간에 자료형을 검사해 적당한 자료형을 선택할 수 있도록 하기 위함
- 객체의 자료형을 컴파일할 때 체크하므로 객체 자료형의 안정성을 높이고 형 변환의 번거로움이 줄어듬
📌 제네릭의 일반적인 사용 방법
⬇️ 제네릭 사용 예시
class Box<T>(t: T) { // 형식 매개변수 T
var name = t
}
fun main() {
val box1: Box<Int> = Box<Int>(1)
val box2: Box<String> = Box<String>("Hello")
// (1) 자료형 생략 가능
val box1 = Box(1)
val box2 = Box("Hello")
println(box1.name)
println(box2.name)
}
-> (1) 객체 생성 시 만일 생성자에서 유추될 수 있는 자료형이 있다면 선언된 자료형인 <String>
이나 <Int>
는 생략 가능
-> 형식 매개변수 T를 이용해 인자의 자료형을 고정할 수 없거나 예측할 수 없을 는 경우 실행 시간에 자료형을 결정할 수 있게 됨
📌 제네릭에서 사용하는 형식 매개변수 이름
형식 배개변수 이름 | 의미 |
---|---|
E | 요소(Element) |
K | 키(Key) |
N | 숫자(Number) |
T | 형식(Type) |
V | 값(Value) |
S,U,V etc. | 두 번째, 세 번째, 네 번째 형식 |
class MyClass<T> { // 1개의 형식 매개변수를 가지는 클래스
// (1) !오류! 형식 매개변수는 프로퍼티에 사용하는 경우 클래스 내부에서 사용 불가
var myProp: T
fun myMethod(a: T) { } // 메서드의 매개변수 자료형에 사용
}
-> (1) 자료형이 특정되지 못하므로 인스터스 생성 불가.
⬇️주 생성자, 부 생성자에 형식 매개변수 지정하기
class MyClass<T>(val myProp: T) {} // 주 생성자의 프로퍼티
class MyClass<T> {
val myProp: T // 프로퍼티
constructor(myProp: T) { // 부 생성자 이용
this.myProp = myProp
}
}
fun main() {
// 주 생성자 myProp에는 12가 할당되며 Int형으로 결정
var a = MyClass<Int>(12)
}
-> 객체 a가 생성되면서 자료형이 Int형으로 결정되며 생서자에 의해 12가 myProp에 초기화
📌 형식 매개변수의 null 제어
⬇️ 형식 매개변수 null 제한하기
class GenericNull<T: Any> { }
fun main() {
val obj = GenericNull<Int?>() // !오류! null 허용 X
}
-> 형식 매개변수는 null이 아닌 Any로 제한하여 null을 지정할 수 없게 함
fun <형식 매개변수[,...]> 함수 이름(매개변수: <매개변수 자료형>[,...]: <반환 자료형>
fun <T> genericFunc(arg: T): T? {...} // 배개변수와 반환 자료형에 형식 매개변수 사용
fun <K, V> put(key: K, value: V): Unit {...} // 형식 매개변수가 2개
📌 제네릭과 람다식
fun <T> add(a: T, b: T) {
return a + b // !오류! 자료형을 아직 결정할 수 없음
}
⬇️ 람다식에서 제네릭 사용
fun <T> add(a: T, b: T, op: (T, T) -> T): T {
return op(a, b)
}
fun main() {
val result = add(2, 3) { a, b -> a + b }
println(result)
}
⬇️ 코드의 가독성을 높이기 위해 람다식만 변수로 정의하기
// 변수 선언부가 있는 경우 표현식의 자료형 생략
var sumInt: (Int, Int) -> Int = {a, b -> a + b}
// 변수 선언부가 생략된 경우에는 표현식에 자료형 표기
var sumInt2: {a:Int, b:Int -> a + b}
...
println(add(2, 3, sumInt))
println(add(2, 3, sumInt2))