farmeter / random

0 stars 0 forks source link

Kotlin. Class와 Interface #52

Open farmeter opened 2 years ago

farmeter commented 2 years ago

이번장은?

4.1 클래스 계층 정의

4.1.1 코틀린 인터페이스

코틀린 선언은 기본적으로 final이며 public

class Button : Clickable { override fun click() = println("I was clicked") }


- 자바에서는 `extends`와 `implements` 키워드를 사용, 코틀린에서는 클래스 이름에 콜론(`:`) 사용
    - 자바와 마찬가지로 클래스는 인터페이스는 원하는 만큼 개수 제한없이 구현 가능, 클래스는 하나만 확장 가능
- `override` 변경자를 꼭 사용해야. 상위 클래스에 있는 메소드와 시그니처가 같은 메소드를 `overide` 없이 사용 불가
- 인터페이스 메소드도 디폴트 구현을 제공할 수 있다.
    - 자바8과 같이 `default`를 붙일 필요 없이, 그냥 메소드 본문을 시그니처 뒤에 추가하면 된다.

```kt
interface Clickable {
    fun click()
    fun showOff() = println("I'm clickable!") // default 구현
}

interface Focusable {
    fun setFocus(b: Boolean) =
        println("I ${if (b)} focus.")
    fun showOff() = println("I'm clickable!") 
}

4.1.2 open, final, abstract 변경자 : 기본적으로 final

//java
final class A {}
class B { //A class 상속 불가 
    final test() {// 오버라이딩 불가}
}
open class RichButton : Clickable { //open 클래스로 상속 가능함.
    fun disable() {}                // final 함수로 오버라이드 불가능.
    open fun animate() {}           // 오버라이드 가능
    override fun click() {}         // *오버라이드한 함수는 기본적으로 open*
    final override fun click2() {}  // 오버라이드 불가
}

4.1.3 접근 제한자(visibility modifier) : 기본적으로 public

4.1.4 내부 클래스와 중첩된 클래스

interface State: Serializable

interface View {
    fun getCurrentState(): State
    fun restoreState(state: State) {}
}

class Button : View {
    override fun getCurrentState(): State = ButtonState()
    override fun restoreState(state: State) {/**/}
    class ButtonState : State{/**/} //자바의 static class와 동일
}

class Outer {
    inner class Inner {
        fun getOuterReference(): Outer = this@Outer // 바깥 클래스 Outer의 참조에 접근
    }
}

4.1.5 봉인된 클래스: 클래스 계층 정의 시 계층 확장 제한

sealed class Expr {
    class Num(val value: Int) : Expr()
    class Sum(val left: Expr, val right: Expr) : Expr()
}

4.2 뻔하지 않은 생성자와 프로퍼티를 갖는 클래스 선언

4.2.1 클래스 초기화: 주 생성자

class User(_nickname: String) { val nickname = _nickname }

class User(val nickname: String, val isSubscribed: Boolean = true) ...

val gil = User("길동") println(gil.isSubscribed) true val gil2 = User("길동2", false) println(gil2.isSubscribed) false val gil3 = User("길동3", isSubscribed=false) println(gil3.isSubscribed) false

4.2.2 부 생성자

class MyButton : View { constructor(ctx: Context) : super(ctx) { // 상위 클래스의 생성자를 호출 //... } constructor(ctx: Context, attr: AttributeSet) : super(ctx) { //... }

}


## 4.2.3 인터페이스에 선언된 프로퍼티 구현
- 인터페이스에 추상 프로퍼티 선언을 넣을 수 있다.
```kt
interface User {
    val nickname: String
    // 이는 User 인터페이스를 구현하는 클래스가 nickname의 값을 얻을 수 있는 방법을 제공해야 한다는 의미
}

class PrivateUser(override val nickname: String) : User //주생성자

class SubscribingUser(val email: String) : User {
    override val nickname: String
        get() = email.substringBefore('@') //custom getter
}

class FacebookUser(val accountId: String) : User {
    override val nickname: getFacebookName(accontId)
}

4.2.4 게터와 세터에서 뒷받침하는 필드에 접근

4.3 컴파일러가 생성한 메소드: 데이터 클래스와 클래스 위임

4.3.1 모든 클래스가 정의해야 하는 메소드

class Client(val name: String, val postalCode: Int) { override fun equlas(other: Any?): Boolean if(other == null || other !is Client) //null 및 타입검사 return false return name == other.name && postalCode == other.postalCode }


- Any는 java.lang.Object에 대응하는 모든 클래스의 최상 클래스

- 해시 컨테이너 : `hashCode()`
- Hash를 사용한 Collections 등에서는 equals()가 true를 반환하는 두 객체는 반드시 같은 hashCode()를 반환해야 한다.

```kt
class ...
    override fun hashCode(): Int = name.hashCode() * 31 + postalCode

4.3.2 데이터 클래스: 모든 클래스가 정의해야 하는 메소드 자동 생성

...
fun copy(name: String = this.name, postalCode: Int = this.postalCode) = Client(name, postalCode)

4.3.3 클래스 위임: by 키워드 사용

class DelegatingCollection<T> : Collection<T> {
    private val innerList = arrayListOf<T>()

    override val size: Int get() = innerList.size
    override fun isEmpty() ...
    override fun contains() ...
    ...
    //기본적으로 인터페이스에서 정의된 모든 fun을 override해야함
}

대신

class DelegatingCollection<T> (
    innerList: Collection<T> = ArrayList<T>()
) : Collection<T> by innerList<> {//    Collection의 구현을 innerList에게 위임한다.
    override fun add(...) //내가 필요한 메소드만 새로운 구현이 가능하다.
}

4.4 object 키워드 : 클래스 선언과 인스턴스 생성

4.4.1 객체선언 : 싱글턴을 쉽게 만들기

//예제 : 파일 경로를 대소문자 없이 구분해주는 Comparator를 구현
object CaseInsensitiveFileComparator : Comparator<File> {
    override fun compare(file1: File, file2: File): Int {
        return file1.path.compareTo(file2.path, ignoreCase = true)
    }
}
>>> println(CaseInsensitiveFileComparator.compare(File("/USER",File("/user")))
0

4.4.2 동반 객체 : 팩토리 메소드와 정적 멤버가 들어갈 장소

class Person(..) { companion object: JSONFactory { override fun fromJson(...) ... //동반 객체가 인터페이스를 구현한다. } }



# 4.5 요약
- 코틀린 인터페이스는 디폴트 구현을 포함할 수 있고, 프로퍼티도 포함할 수 있다.
- 기본적으로 `final`, `public` 이다.
- `open`을 사용해서 상속과 오버라이딩을 허용할 수 있다.
- `internal` 선언은 같은 모듈 안에서만 볼 수 있다.
- 중첩 클래스와 `inner`를 사용한 내부클래스를 사용할 수 있다.
- 주 생성자, 부생성자를 활용할 수 있다.
- `data` 키워드를 이용해서 컴파일러가 `equals, hashCode, toString, copy` 등을 자동으로 생성해준다.
- `by` 키워드를 이용하여 위임패턴을 구현할 수 있다.
- `companion` 키워드를 이용해 객체선언을 사용할 수 있다.