728x90

Kotlin에서 List, Map, Set같은 Collections 클래스를 사용할 때, List<String> 이런식으로 제네릭 타입을 지정할 수 있다.

제네릭을 사용하면 타입 안정성을 얻을 수 있다.
하지만 제네릭으로 지정한 타입 이외에도 좀 더 유연하게 사용하고 싶을 수 있다.
그래서 코틀린에서는 공변성과 반공변성을 허용한다.

 

package generic
 
abstract class Animal(val name: String)
 
abstract class Fish(name: String) : Animal(name)
 
// 금붕어
class GoldFish(name: String) : Fish(name)
 
// 잉어
class Carp(name: String) : Fish(name)

 

package generic
 
fun main(){
    val goldFishCage = Cage<GoldFish>()
    goldFishCage.put(GoldFish("금붕어")) // Type Casting없이 바로 금붕어를 가져올 수 있다.
 
    val cage = Cage<Fish>()
    cage.moveFrom(goldFishCage)
 
    val fish: Fish = cage.getFirst()
    // Cage<Fish>에서 데이터를 가져오면 GoldFish인지 Carp인지 모른다.
}
 
/***
 * 제네릭 클래스 : 타입 파라미터를 사용한 클래스
 * 코틀린에서는 Raw 타입 사용이 불가능하다.
 * Raw Type : 제네릭 클래스에서 타입 매개변수를 사용하지 않고 인스턴스화 하는 것
 * in-variant(무공변) : 타입 파라미터끼리는 상속관계이더라도, 제네릭 클래스 간에는 상속관계가 없다는 의미
 * co-variant(공변) : 타입 파라미터간의 상속관계가 제네릭 클래스에도 동일하게 유지된다는 의미
 * 코틀린에서는 타입 파리미터 앞에 out 변성 어노테이션을 사용한다.
 * contra_variant(반공변) : 타입 파라미터간의 상속관계가 제네릭 클래스에서는 반대로 유지된다는 의미
 * 코틀린에서는 타입 파리미터 앞에 in 변성 어노테이션을 사용한다.
 */
class Cage<T : Animal> {
    private val animals: MutableList<T> = mutableListOf()
 
    fun getFirst() : T {
        return animals.first();
    }
 
    fun getAll() : List<T> {
        return  this.animals
    }
 
    fun put(animal: T) {
        this.animals.add(animal)
    }
 
    fun moveFrom(otherCage: Cage<out T>) {
        // out을 붙이면 moveFrom 함수를 호출할 때 Cage는 공변하게 된다.
        // out을 붙이면, otherCage로부터 데이터를 꺼낼 수만 있다.
        this.animals.addAll(otherCage.animals)
    }
 
    fun moveTo(otherCage: Cage<in T>){
        // in을 붙인 otherCage는 데이터를 받을 수만 있다.
        otherCage.animals.addAll(this.animals)
    }
}

 

 

 

728x90

'안드로이드 > Kotlin 문법' 카테고리의 다른 글

코틀린 클래스 위임(Class Delegation)  (1) 2024.02.06
[코틀린] ArrayList, mutableListOf  (0) 2021.06.14
[코틀린] Inner Class  (0) 2020.08.21
[코틀린] Nested Class (중첩 클래스)  (0) 2020.08.21
코틀린 클래스  (0) 2020.05.06
블로그 이미지

Link2Me

,