제너릭
클래스나 함수에서 사용하는 자료형을 외부에서 지정할 수 있는 기능
예를들어 클래스A와 A를 상속받은 클래스B있다고 가정해보자.
이 두 클래스의 인스턴스를 공용으로 사용하는 하나의 함수에 패러미터로 받으려면 어떻게 해야할까?
함수의 패러미터 자료형을 슈퍼클래스인 A의 자료형으로 받으면 B는 자동으로 A로 업캐스팅되면서 두 클래스 모두 함수의 패러미터로 사용할 수 있다.
하지만! 캐스팅 연산 거치는 것은 프로그램의 속도를 저하시킬 수 있다는 단점이있다.
그래서 Gerneric 이라는 개념이 나왔다!
제너릭은 함수나 클래스를 선언할 때 고정적인 자료형 대신 실제 자료형으로 대체되는 타입 패러미터를 받아 사용하는 방법이다.
fun<T> genericFunc (param : T) : T
class GenericClass<T> (var pref : T)
이 타입 패러미터에 '특정 자료형'이 할당되면 제너릭을 사용하는 모든 코드는 할당된 자료형으로 대체되어 컴파일 된다. 따라서 캐스팅 연산 없이도 자료형을 그대로 사용 할 수 있는 것이다.
<T> 타입 패러미터의 이름은 클래스 이름과 규칙이 같지만 일반적으로 'Type'의 이니셜인 'T'를 사용하는 것이 관례이며, 여러개의 제너릭을 사용할 경우 T의 다음 알파벳인 <T,U,V>를 추가적으로 사용하기도 한다.
또한 제너릭을 특정한 수퍼 클래스를 상속받은 클래스 타입으로만 제한하려면 콜론(:)을 쓰고 슈퍼클래스명을 명시하면 된다.
ex) <T:SuperClass>
제너릭 사용법
함수제너릭
fun<T> genericFunc (var param : T) { … } // 함수에 제너릭을 선언한 경우
일반적인 함수처럼 사용하면 gernericFunc(1) 패러미터나 반환형을 통해 타입패러미터를 자동으로 추론해준다.
클래스제너릭
class Box<T> (t: T)
클래스의 경우 인스턴스를 만들때
- GenericClass<int> ( ) // 수동으로 지정하거나
- class GenericClass<T> (var pref: T) // 생성자에 제너릭이 사용된경우
지정하지 않아도 자동으로 추론된다. GenericClass(1)
fun main(){
UsingGeneric(A()).doShouting()
UsingGeneric(B()).doShouting()
UsingGeneric(C()).doShouting()
doShouting(B()) // 캐스팅없이 B의 객체 그대로 함수에서 사용하는것
}
fun <T: A> doShouting(t:T){
t.shout()
}
open class A{
open fun shout() {
println("A가 소리칩니다.")
}
}
class B : A(){
override fun shout(){
println("B가 소리칩니다")
}
}
class C : A() {
override fun shout(){
println("C가 소리칩니다.")
}
}
class UsingGeneric<T: A> (val t : T){
fun doShouting(){
t.shout()
}
}
*출력결과 :
A가 소리칩니다.
B가 소리칩니다.
C가 소리칩니다.
제너리을 사용하지 않고 UsingGeneric의 생성자에서 슈퍼클래스인 A로 캐스팅하여 shout을 호출하여도 동작은 같겠지만 (class UsingGeneric(val t: A)) 이렇게 (class UsingGeneric<T:A>(val t : T) 제너릭을 사용하는 경우, 사용할 때 generic이 자료형을 대체하게 되어 캐스팅을 방지할 수 있으므로 성능을 더 높일 수 있다.
제너릭은 많은 기본 클래스에서도 사용되고 있다.
'코틀린' 카테고리의 다른 글
코틀린(18) - 문자열 관련 함수 (0) | 2022.03.23 |
---|---|
코틀린(17) - 컬렉션 객체, 리스트 (0) | 2022.03.23 |
코틀린(15) - 다형성 (0) | 2022.03.23 |
코틀린(14) - 람다함수를 이용한 스코프 함수 (0) | 2022.03.21 |
코틀린(13) - 고차함수, 람다함수 (0) | 2022.03.21 |
댓글