728x90
반응형
✅ object 키워드 : 클래스 선언과 인스턴스 생성
- 코틀린에서는 object 키워드를 다양한 상황에서 사용하지만 모든 경우 클래스를 정의하면서 동시에 인스턴스(객체)를 생성한다는 공통점이 있음
- object 키워드를 사용하는 상황은 다음과 같음
- 객체 선언(Object Declaration) : 싱글턴을 정의하는 방법 중 하나
- 동반 객체(Companion Object) : 인스턴스 메서드는 아니지만 어떤 클래스와 관련 있는메서드와 팩토리 메서드를 담을 때 사용
- 동반 객체 메서드에 접근할 때는 동반 객체가 포함된 클래스의 이름을 사용할 수 있음
- java의 static과 같음
- 객체 식은 자바의 무명 내부 클래스 대신 쓰임
📌 객체 선언 : 싱글턴을 쉽게 만들기
- 자바에서는 보통 클래스의 생성자를 private으로 제한하고 정적인 필드에 그 클래스의 유일한 객체를 저장하는 싱글턴 패턴을 통해 이를 구현함
- 반면에 코틀린은 객체 선언 기능을 통해 싱글턴을 언어에서 기본 지원함
- 객체 선언은 클래스 선언과 그 클래스에 속한 단일 인스턴스의 선언을 합친 선언
- 객체 선언은 object 키워드로 시작
- 객체 선언은 클래스를 정의하고 그 클래스의 인스턴스를 만들어서 변수에 저장하는 모든 작업을 단 한 문장으로 처리함
- 생성자 호출 없이 즉시 만들어지기 때문에 주, 부 생성자 모두 존재할 수 없음
object CaseInsensitiveFileComparator : Comparator<File> {
override fun compare(file1: File, file2: File): Int {
return file1.path.compareTo(file2.path, ignoreCase = true)
}
}
fun main(args: Array<String>) {
println(CaseInsensitiveFileComparator.compare(
File("/User"), File("/user")))
val files = listOf(File("/Z"), File("/a"))
println(files.sortedWith(CaseInsensitiveFileComparator))
}
- 객체 선언도 클래스나 인터페이스를 상속할 수 있음
- 프레임워크를 사용하기 위해 특정 인터페이스를 구현해야 하는데, 그 구현 내부에 다른 상태가 필요하지 않은 경우에 이런 기능이 유용함
📌 동반 객체 : 팩토리 메소드와 정적 멤버가 들어갈 장소
- Kotlin에서는 static을 지원하지 않기 때문에 정적인 멤버가 없음
- 그 대신 최상위 함수와 객체 선언을 활용해 정적 메소드 역할을 대신할 수 있음
- 하지만 최상위 함수는 클래스의 private 멤버에 접근할 수 없음
- 따라서 클래스 내부에 객체를 만들어서 이용하게 되는데 이때, 클래스 내부에 객체를 동반 객체로 만들어 활용
- 동반 객체
- 클래스 안에 정의된 객체 중 하나에 companion이라는 특별한 표시를 붙이면 그 클래스의 동반 객체를 만들 수 있음
- 동반 객체의 프로퍼니타 메서드에 접근하려면 그 동반 객체가 정의된 클래스 이름을 사용 (이름을 따로 지정할 필요 없음)
class A {
companion object {
fun bar() {
println("Companion object called")
}
}
}
A.bar() // Companion object called
- 동반 객체는 private 생성자를 호출하기 좋은 위치
- 동반 객체는 자신을 둘러싼 클래스의 모든 private 멤버에 접근할 수 있음
class User private constructor(val nickname: String) {
companion object {
fun newSubscribingUser(email: String) =
User(email.substringBefore('@'))
fun newFacebookUser(accountId: Int) =
User(getFacebookName(accountId))
}
}
fun main(args: Array<String>) {
val subscribingUser = User.newSubscribingUser("bob@gmail.com")
val facebookUser = User.newFacebookUser(4)
println(subscribingUser.nickname)
}
📌 동반 객체를 일반 객체처럼 사용
- 동반 객체는 클래스 안에 정의된 일반 객체
- 따라서 동반 객체에 이름을 붙이거나, 동반 객체가 인터페이스를 상속하거나, 동반 객체 안에 확장 함수와 프로퍼티를 정의할 수 있음
class Person(val name: String) {
companion object Loader {
fun fromJSON(jsonText: String) : Person = ... // 동반 객체에 이름을 붙인다
}
}
person = Person.Loader.fromJSON("{name: 'Dmitry'}")
person.name // Dmitry
person2 = Person.fromJSON("{name: 'Brent'}")
person2.name // Brent
- 대부분의 경우 클래스 이름을 통해 동반 객체에 속한 멤버를 참조할 수 있으므로 객체의 이름을 짓느라고 고심할 필요가 없음
- 필요한 경우 위의 예제처럼 companion object Loader 같은 방식으로 동반 객체에도 이름을 붙일 수 있음
- 특별히 이름을 지정하지 않으면 동반 객체 이름은 자동으로 Companion이 됨
❗️ 동반 객체에서 인터페이스 구현
- 다른 객체 선언과 마찬가지로 동반 객체도 인터페이스를 구현할 수 있음
interface JSONFactory<T> {
fun fromJSON(jsonText: String): T
}
class Person(val name: String) {
companion object : JSONFactory<Person> {
override fun fromJSON(jsonText: String): Person = ... // 동반 객체가 인터페이스를 구현한다.
}
}
📌 객체 식 : 무명 내부 클래스를 다른 방식으로 작성
- 무명 객체(Anonymous Object)를 정의할 때도 object 키워드를 씀
- 무명 객체는 자바의 무명 내부 클래스를 대신함
window.addMouseListener(
object : MouseAapter() { // MouseAdapter를 확장하는 무명 객체를 선언
override fun mouseclicked(e: MouseEvent) { // MouseAdapter의 메서드를 오버라이드
// ...
}
override fun mouseEntered(e : MouseEvent) { // MouseAdapter의 메서드를 오버라이드
// ...
}
}
}
- 한 인터페이스만 구현하거나 한 클래스만 확장할 수 있는 자바의 무명 내부 클래스와 달리 코틀린 무명 클래스는 여러 인터페이스를 구현하거나 클래스를 확장하면서 인터페이스를 구현할 수 있음
- 자바의 무명 클래스와 같이 객체 식 안의 코드는 그 식이 포함된 함수의 변수에 접근할 수 있음
- 하지만 자바와 달리 final이 아닌 변수도 객체 식 안에서 사용할 수 있음
728x90
반응형
'Studying > Kotlin' 카테고리의 다른 글
[Kotlin In Action] 5장. 람다로 프로그래밍(2) - 컬렉션 함수형 API (0) | 2023.05.18 |
---|---|
[Kotlin In Action] 5장. 람다로 프로그래밍(1) - 람다 식과 멤버 참조 (0) | 2023.05.17 |
[Kotlin In Action] 4장. 클래스, 객체, 인터페이스(3) - 컴파일러가 생성한 메서드 : 데이터 클래스와 클래스 위임 (0) | 2023.05.16 |
[Kotlin] 코틀린의 Scope Function(범위 지정 함수) (0) | 2023.05.16 |
[Kotlin In Action] 4장. 클래스, 객체, 인터페이스(2) - 뻔하지 않은 생성자와 프로퍼티를 갖는 클래스 선언 (2) | 2023.05.11 |