04. 클래스, 객체, 인터페이스
클래스
코틀린은 자봐와 달리 콜론(:)을 붙이고 인터페이스와 클래스 이름을 적는 것으로 클래스 확장과 인터페이스 구현을 모두 처리한다.
오버라이딩할땐 반드시 override
변경자를 사용해야 한다.
상속한 인터페이스의 메서드 구현 호출하기 ```kotlin class Button : Clickable, Focusable { override fun click() = println(“I was clicked”)
// 이름과 시그니처가 같은 멤버 메서드에 대해 둘 이상의 디폴트 구현이 있는 경우
// 인터페이스를 구현하는 하위 클래스에서 명시적으로 새로운 구현을 제공해야 한다.
override fun showOff() {
super<Clickable>.showOff()
super<Focusable>.showOff()
}
}
```
클래스와 메서드는 기본적으로 final이다. 취약한 기반 클래스 문제(하위 클래스가 base 클래스에 대해 가졌던 가정이 base 클래스를 변경함으로써 깨져버림)로 인해 상속을 최소화하고 싶은 것이다.
클래스 내에서 상속 제어 변경자 의미
변경자 | 이 변경자가 붙은 멤버는… | 설명 |
---|---|---|
final |
오버라이드 할 수 없음 | 클래스 멤버의 기본 변경자다. |
open |
오버라이드 할 수 있음 | 반드시 open을 명시해야 오버라이드 할 수 있다. |
abstract |
반드시 오버라이드해야 함 | 추상 클래스의 멤버에만 이 변경자를 붙일 수 있다. 추상 멤버에는 구현이 있으면 안된다. |
override |
상위 클래스나 상위 인스턴스의 멤버를 오버라이드하는 중 | 오버라이드 하는 멤버는 기본적으로 열려있다. 하위 클래스의 오버라이드를 금지하려면 final을 명시해야 한다. |
코틀린에선 internal
가시성 변경자를 사용하면 같은 모듈 안에서만 볼 수 있다.
코틀린에선 최상위 선언에 대해 private 가시성을 허용한다.
protected
멤버는 오직 어떤 클래스나 그 클래스를 상속한 클래스 안에서만 보인다.
자바와 코틀린의 중첩 클래스와 내부 클래스 관계
| 클래스 B 안에 정ㅇ의된 클래스 A | 자바에서 | 코틀린에서 |
| 중첩 클래스(바깥쪽 클래스에 대한 참조를 저장하지 않음) |static class A
|class A
|
| 내부 클래스(바깥쪽 클래스에 대한 참조를 저장함)| class A
|inner class A
|
sealed
변경자를 사용하면 그 상위 클래스를 상속한 하위 클래스 정의를 제한할 수 있다. 따라서 when
을 사용할 때 따로 else 분기를 만들지 않아도 괜찮다.
객체의 동등성: 코틀린에서 ==
연산자는 객체의 동등성을 검사한다. 따라서 비교할 때는 equals를 override해줘야 한다. 그런데 이때 객체가 제대로 작동하지 않는 경우가 있다. 그 이유는 hashCode를 정의하지 않았기 때문이다. 하 근데 이런거 다 재정의해주려면 힘들다. 그래서 코틀린은 data class
를 만들어서 toString
, equals
, hashCode
와 같은 메서드를 정의해주고 정확성과 일관성을 한 번더 검사해준다.
05. 람다
람다는 기본적으로 다른 함수에 넘길 수 있는 작은 코드 조각을 뜻한다.
- 사용
- 이벤트 발생시 핸들러 실행
- 데이터 구조의 모든 원소에 이 연산을 적용
- 위험성
- 람다를 이벤트 핸들러나 다른 비동기적으로 실행되는 코드로 활용하는 경우 함수 호출이 끝난 다음에 로컬 변수가 변경 될 수 있다.
fun click(button: Button): Int { var clicks = 0 button.onClick { clicks++ } return clicks // 항상 0을 반환함 (핸들러가 clicks를 반환한 뒤 호출되기 때문) }
- 람다를 이벤트 핸들러나 다른 비동기적으로 실행되는 코드로 활용하는 경우 함수 호출이 끝난 다음에 로컬 변수가 변경 될 수 있다.
- 멤버참조 (
::
)
people.maxBy(Person::age)
==people.maxBy{ it.age }
==people.maxBy{ p -> p.age }
count
vssize
people.filter(canBeInClub).size
이런 코드를 살펴 보자.해당 코드에선 조건을 만족하는 모든 원소가 들어가는 중간 컬렉션이 생겨 오히려 불필요하다.
count
를 사용하게 되면 조건을 만족하는 원소의 개수만을 추적하지 원소를 따로 저장하진 않기에 더 효율적이다.
count
가 더 효율적!
지연 계산 컬렉션 계산
시퀀스를 사용하면 중간 임시 컬렉션을 사용하지 않고도 컬렉션 연산을 연쇄할 수 있다.
asSequence
확장 함수를 호출하면 어떤 컬렉션이든 시퀀스로 바꿀 수 있다.
시퀀스를 사용하면 더 효율적이기 때문에 큰 컬렉션에 대해 연산을 연쇄할 땐 이걸 쓰자!!!