제네릭(Generic)
fun <T> wrap(value: T) {
println(value)
}
fun main() {
wrap(1)
wrap("abc")
wrap(1.3)
}
//1
//abc
//1.3
불변성(Invariance)
open class Animal
class Cat : Animal()
class Dog : Animal()
val cats: Array<Cat> = arrayOf(Cat(), Cat())
// Error - Type mismatch: inferred type is Array<Cat> but Array<Animal> was expected
val animals: Array<Animal> = cats
-> 여기서 컴파일 에러가 발생하니다. 즉, A가 B를 상속받아도 Class<'A'>는 Class<'B'>를 상속받지 않는다라는 것입니다.
fun myAnimals(animals: Array<Animal>) {
animals[0] = Dog() // Array<Cat> cats[0] = Dog() (??!)
}
fun main() {
val cats: Array<Cat> = arrayOf(Cat(), Cat())
myAnimals(cats)
}
-> Cat 자료형의 ArrayList에 Dog타입의 값이 들어가므로 문제가 발생한다.
하지만 아래의 코드는 에러가 발생하지 않는다.
fun myAnimals(animals: List<Animal>) {
println(animals[0])
}
fun main() {
val cats: List<Cat> = listOf(Cat(), Cat())
myAnimals(cats)
}
->차이는 Array를 List로 바꿨을 뿐입니다. Array는 값을 바꿀 수 있는 가변, List는 값을 바꿀 수 없는 불변입니다.
Array와 List의 내부 선언의 형태는 아래와 같은데 out/in에 대해서는 밑에서 알아보도록 합니다.
public class Array<T>
public interface List<out E>
<'out T'>, 공변성으로의 변환
fun copyFromTo(from: Array<Animal>, to: Array<Animal>) {
for (i in from.indices) {
to[i] = from[i]
}
}
fun main() {
val animals: Array<Animal> = arrayOf(Animal(), Animal())
val cats: Array<Cat> = arrayOf(Cat(), Cat())
// Error - Type mismatch: inferred type is Array<Cat> but Array<Animal> was expected
copyFromTo(cats,animals)
}
-> Animal 타입의 리스트에 Cat 타입의 리스트 요소를 넣는 과정은 문제가 발생하지 않지만, A가 B를 상속받아도 Class<'A'>는 Class<'B'>를 상속받지 않는다 라는 불변성의 원리로 컴파일 에러가 발생합니다.
fun copyFromTo(from: Array<out Animal>, to: Array<Animal>) {
for (i in from.indices) {
to[i] = from[i]
}
}
fun main() {
val animals: Array<Animal> = arrayOf(Animal(), Animal())
val cats: Array<Cat> = arrayOf(Cat(), Cat())
copyFromTo(cats,animals)
}
<'int T'>, 반공변성으로의 변환
fun copyFromTo(from: Array<out Animal>, to: Array<Animal>) {
for (i in from.indices) {
to[i] = from[i]
}
}
fun main() {
val anys: Array<Any> = arrayOf(Any(), Any())
val cats: Array<Cat> = arrayOf(Cat(), Cat())
// Error - Type mismatch: inferred type is Array<Any> but Array<Animal> was expected
copyFromTo(cats,anys)
}
-> 역시나 위 코드에서는 문제가 발생하는데, 이를 해결하기 위해서는 A가 B를 상속받으면 Class<'B'>는 Class<'A'>를 상속받는다로 바꿔주어야 한다. 이를 반공변성이라 하며 키워드는 in이다.
fun copyFromTo(from: Array<out Animal>, to: Array<in Animal>) {
for (i in from.indices) {
to[i] = from[i]
}
}
fun main() {
val anys: Array<Any> = arrayOf(Any(), Any())
val cats: Array<Cat> = arrayOf(Cat(), Cat())
copyFromTo(cats,anys)
}