본문 바로가기
코틀린

코틀린(16) - 제너릭

by 왈레 2022. 3. 23.

제너릭

클래스나 함수에서 사용하는 자료형을 외부에서 지정할 있는 기능

 

예를들어 클래스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 자료형을 대체하게 되어 캐스팅을 방지할 있으므로 성능을 높일 있다.

 

제너릭은 많은 기본 클래스에서도 사용되고 있다.

댓글