카테고리 없음

[Kotlin 27강] Generic

연나연 2024. 1. 8. 10:19

Generic

클래스를 설계할 때 변수의 타입을 유동적으로 하고 싶을 때가 있을 수도 있다.
이 때 Generic 개념을 활용하면 클래스 작성시가 아닌 객체 생성시에 변수의 타입을 설정할 수 있다.
// Generic : 클래스를 작성할 때 프로퍼티, 매개변수 등에 설정되는 자료형을 객체를 생성할 때
// 결정할 수 있도록 하는 개념

fun main(){
    // 제네릭 타입은 객체를 생성할 때 타입을 결정해줘야 한다.
    // T 타입으로 정의된 변수의 타입이 Int 로 결정된다.
    val t1 = TestClass1<Int>()
    t1.testMethod1(100)
    println()

    val t2 = TestClass1<String>()
    t2.testMethod1("안녕하슈")
    println("---------------------------")

    val t3 = TestClass2<Int, Double, Boolean, String>(100,11.11)
    t3.testMethod3(true,"문자열1")
    println("---------------------------")

    val t4 = TestClass2<Double, String, Boolean, Int>(22.22, "문자열2")
    t4.testMethod3(false, 200)
}

// < > : 안에 알바벳 문자를 넣어준다. 보통 대문자 한글자를 작성한다.
// 이 알파벳은 아직 결정되지 않은 타입을 의미한다.
// 어떠한 타입인지 결정되지 않았지만 이 타입의 변수들을 정의하여 클래스를 작성하고
// 향후, 객체를 생성할 때 타입을 결정할 수 있다.
class TestClass1<T>{
    fun testMethod1(a1:T){
        println("a1 : $a1")
    }
}

class TestClass2<A, B, C, D>(var a1:A, var a2:B){
    fun testMethod3(a3:C, a4:D){
        println("a1 : $a1")
        println("a2 : $a2")
        println("a3 : $a3")
        println("a4 : $a4")
    }
}

open class SuperClass1
open class SubClass1() : SuperClass1()
class Subclass2 : SubClass1()

// 불변성
class TestClass3<T>​
가변성

불변성 : 제네릭이 설정된 객체의 주소 값을 같은 타입의 제네릭이 설정된 변수에만 담을 수 있다.
공변성 : 제네릭이 설정된 객체의 주소 값을 부모 클래스 타입의 제네릭이 설정된 변수에도 담을 수 있다(out)
반 공변성 : 제네릭이 설정된 객체의 주소 값을 자식 클래스 타입의 제네릭이 설정된 변수에도 담을 수 있다(in)

 

이 부분은 좀 복잡하고 크게 쓸 일 없으니, 그냥 이런게 있다! + 개념정도만 알아두자

 

fun main(){
    
    // 불변성 : 객체를 생성할 때 설정한 제네릭과 같은 변수에 담을 수 있다.
    // 클래스간의 상속 관계에 상관없이 제네릭에 설정한 클래스 타입이 다르면 오류가 발생한다.
    val t5:TestClass3<SubClass1> = TestClass3<SubClass1>()
    //val t6:TestClass3<SuperClass1> = TestClass3<SubClass1>()
    //val t7:TestClass3<Subclass2> = TestClass3<SubClass1>()

    // 공변성 : 변수에 설정한 제네릭이 객체를 생성했을 때 사용한 제네릭과 같거나 부모 클래스인 경우에
    // 담을 수 있다.
    val t8:TestClass4<SubClass1> = TestClass4<SubClass1>()
    val t9:TestClass4<SuperClass1> = TestClass4<SubClass1>()
    // val t10:TestClass4<SubClass2> = TestClass4<SubClass1>()

    // 반 공변성 : 변수에 설정한 제네릭이 객체를 생성했을 때 사용한 제네릭과 같거나 자식 클래스인 경우에
    // 담을 수 있다.
    val t11:TestClass5<SubClass1> = TestClass5<SubClass1>()
    // val t12:TestClass5<SuperClass1> = TestClass5<SubClass1>()
    val t13:TestClass5<SubClass2> = TestClass5<SubClass1>()
}


// 불변성 (제네릭에 키워드를 붙히지 않는다)
class TestClass3<T>
// 공변성
class TestClass4<out A>()
// 반공변성
class TestClass5<in A>()