Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- recyclerview
- onMeasure
- sqlite
- LiveData
- BOJ
- activity
- room
- DataBinding
- 백준
- View
- 코틀린
- 알고리즘
- lifecycle
- CustomView
- Coroutine
- Behavior
- hilt
- Navigation
- HTTP
- AppBarLayout
- Algorithm
- Android
- onLayout
- notification
- CollapsingToolbarLayout
- CoordinatorLayout
- 알림
- 안드로이드
- ViewModel
- kotlin
Archives
- Today
- Total
개발일지
Kotlin in A..Z (26) - 상, 하위 형식의 가변성 본문
가변성
- 가변성이란 매개변수가 클래스에 영향을 주는 것을 말한다.
- 예를 들어 Int클래스는 Number클래스를 상속받았고, Number클래스 변수에 Int의 인스턴스를 대입할 수 있다. 이때 Int는 Number의 하위 형식이 된다.
가변성의 3가지 유형
용어 | 의미 |
공변성(Covariance) | A가 B의 하위 형식이면 C<A>는 C<B>의 하위 형식이다. 생산자 입장의 out 성질 |
반공변성(Contravariance) | A가 B의 하위 형식이면 C<B>는 C<A>의 하위 형식이다. 소비자 입장의 in성질 |
무변성 | C<A>와 C<B>는 아무 관계가 없다. 생산자 + 소비자 |
무변성
기본 값이다.
Any -> Number -> Int의 관계가 있지만 무변성이 적용되면 아무 관계가 없기 때문에 Type mismatce가 발생한다.
class Box<T>
fun main() {
val any: Box<Any> = Box<Number>() // Error Type mismatch
val int: Box<Int> = Box<Number>() // Error Type mismatch
}
공변성 (out)
Any -> Number관계이기 때문에 Any에 Number을 대입할 수 있다
Number -> Int관계에서는 Int에 Number을 대입할 수 없다.
// 공변성 정의
class Box<out T>
fun main() {
val any: Box<Any> = Box<Number>() // 공변성 Any -> Number이기 때문에 Any에 Number을 대입할 수 있음
val int: Box<Int> = Box<Number>() // Error Type mismatch
}
반공변성 (in)
Any -> Number관계이기 때문에 Any에 Number을 대입할 수 없다
Number -> Int관계에서는 Int에 Number을 대입할 수 있다.
// 반공변성 정의
class Box<in T>
fun main() {
val any: Box<Any> = Box<Number>() // Error Type mismatch
val int: Box<Int> = Box<Number>() // 반공변성 Number -> Int 이기 때문에 Int에 Number을 대입할 수 있음
}
공변성에 따른 자료형 제한
- 공변성(out)은 반환하는 함수만 가질 수 있다.
- 반공변성(in)은 들어오는 함수만 가질 수 있다.
- 공변성을 사용하면 형식 매개변수를 갖는 프로퍼티는 private으로 선언하거나 val로 선언해야 한다. (var로 설정하면 들어오는 함수인 setter가 자동으로 생성되기 때문, private으로 설정하면 setter가 안생기니까)
- 반공병성, 공변성을 사용하면 형식 매개변수를 갖는 프로퍼티는 private으로 선언해야 한다. (val이나 var로 선언하면 getter가 자동으로 생성되기 때문, private으로 설정하면 getter가 생성되지 않는다.)
코드
class Box1<in T> (private var element: T, val h: T){
// Error 반공변성은 반환하는 자료형을 쓸 수 없다.
fun getElement(): T {
return element
}
fun setElement(element: T) {
this.element = element
}
}
class Box2<out T> (private var element: T, val h: T){
fun getElement(): T {
return element
}
// Error 공변성은 들어오는 자료형에는 쓸 수 없다.
fun setElement(element: T) {
this.element = element
}
}
자료형 프로젝션
- 선엄 지점 변성
클래스를 선언하면서 클래서 자체에 가변성을 지정하는 방식
클래스를 선언하면서 전체적으로 지정하기 때문에 클래스를 사용하는 장소에서는 따로 자료형을 지정할 필요가 없다.
코드
// 클래스 정의와 동시에 설정
class Box<out E>(private val element: E) {
}
- 사용 지점 변성
메서드의 매개변수, 제네릭 클래스를 생성할 때 가변성을 지정하는 방식
코드
class Box<E>(val list: ArrayList<E> = ArrayList()) {
}
fun <T> get(index: Int, box: Box<out T>): T {
return box.list[index]
}
- 스타 프로젝션
- Box<Any?>는 모든 자료형을 받을 수 있지만 Box<*>은 구체적으로 자료형이 결정되면 그 자료형과 하위 자료형만 받을 수 있다.
- in으로 정의된 형식 매개변수를 *로 하면 in Nothing으로 취급한다.
- out으로 정의된 형식 매개변수를 *로 하면 out Any?로 취급한다.
코드
class Box<in InE, out OutE> (inE: InE, outE: OutE) {
// Error 반공변성으로 선언했기 때문(public으로 선언했기 때문에 getter가 생긴다 -> 공변성)
val inE = inE
val outE = outE
fun function1(inE: InE) {
println(inE)
}
// Error 공변성으로 선언했기 때문
fun function2(outE: OutE) {
}
}
// Box<Nothing, Any?> 와 같게 잡힌다
fun test(box: Box<*, *>) {
// Error Nothing으로 취급하기 때문에
box.function1(1)
println(box.outE)
}
'Kotlin (코틀린)' 카테고리의 다른 글
Kotlin in A..Z - Array (0) | 2020.07.21 |
---|---|
Kotlin in A..Z (27) - reified (0) | 2020.07.19 |
Kotlin in A..Z (25) - 제네릭 (0) | 2020.07.19 |
Kotlin in A..Z (24) - 연산자 오버라이딩 (0) | 2020.07.18 |
Kotlin in A..Z (23) - 열거형 클래스, 실드 클래스 (0) | 2020.07.17 |
Comments