이 글은 Kotlin In Action을 참고 하였습니다.
더욱 자세한 설명이나 예제는 직접 책을 구매하여 확인 하시기 바랍니다
코틀린은 object란 키워드를 사용합니다.
자바에는 이 키워드가 없죠.
약간 생소할 수 도 있는 이 키워드는 java의 어떤 개념과 매칭되는지 알아봅니다.
4.4 object 키워드, 클래스의 선언과 인스턴스 생성
- 싱글턴을 정의하는 방법
- 동반객체 companion object를 이용한 팩토리 메서드 구현
- 무명클래스(익명 클래스)의 선언
4.4.1 싱글턴 (Singleton)
object Payroll {
val allEmplyoees = arrayListOf()
fun calculateSalary() {
for (person in allEmplyoees) {
....
}
}
}
급여를 계산하는 함수 입니다.
object로 선언하면 클래스 선언과 동시에 객체가 생성됩니다.
Payroll.allEmplyoees .add(Person("홍길동","김말똥")
Payroll.calcualteSalaray()
객체 이름을 통해 property나 메서드에 직접 접근할 수 있습니다.
object 객체 역시 다른 class를 상속하거나 interface를 구현할 수 있습니다.
object CaseInsensitiveFileComparator : Comparator {
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))
}
comparator에 대한 예제 입니다.
comparator는 여러개를 구현할 필요가 없기 때문에 singleton으로 하나만 만들고 사용하면 편리합니다.
직접 compare를 호출해서 사용할 수 도 있고, list에서 sortedWith 함수를 이용하여 객체 자체를 넘겨줄 수도 있습니다.
여기서 sortedWith는 리스트를 정렬하는 함수 입니다.
만약 Person 객체를 정렬하는 comparator를 Person 객체 내부에 구현하고 싶다면 중첩된 class 형태로 구현해도 됩니다.
외부 class의 객체를 여러개 생성하더라도 내부에 존재하는 object는 단일 객체만 존재 합니다.
즉 class 밖에서 선언되나, class 안에서 선언되나, singleton으로 생성됩니다.
data class Person(val name: String) {
object NameComparator : Comparator {
override fun compare(p1: Person, p2: Person): Int =
p1.name.compareTo(p2.name)
}
}
fun main(args: Array<String>) {
val persons = listOf(Person("Bob"), Person("Alice"))
println(persons.sortedWith(Person.NameComparator))
}
Java에서 object 객체를 호출시에는 INSTANCE란 이름을 통해 호출합니다.
Person.NameComparator.INSTANCE.compare(new Person("고길동"), new Person ("도우너"));
4.4.2 companion object
class A {
companion object {
fun bar() {
println("Companion object called")
}
}
}
fun main(args: Array<String>) {
A.bar()
}
클래스 내부에 선언된 companion object는 호출할때 클래스 이름으로 바로 호출할 수 있습니다.
(java의 static 함수와 동일한 형태입니다.)
companion object는 외부 클래스의 private property에도 접근이 가능하기에, factory method를 만들때 적합합니다.
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)
}
user는 private constructor를 가지기 때문에 외부에서 생성할 수 없습니다.
다라서 외부에서는 companion으로 제공되는 factory method를 이용해서만 객체를 생성할 수 있도록 제한할 수 있습니다.
4.4.3 companion object의 사용
companion object는 클래스 내부에 정의된 일반 객체입니다.
따라서 아래와 같은 작업이 가능합니다.
- companion object에 이름 명명
- companion object 내부에 확장 함수나 property 정의
- 인터페이스 상속
class Person(val name: String) {
companion object Loader {
fun fromJSON(jsonText: String): Person = ....
}
}
fun main(args: Array<String>) {
person1 = Person.Loader.fromJSON("{name:'hong'}")
person2 = Person.fromJSON("{name:'kim'}")
}
companion object에 이름을 붙일수 있으며, 이름을 통해서 호출할 수 도 있고, 그냥 호출할 수 도 있습니다.
interface JSONFactory<T> {
fun fromJSON(jsonText: String): T
}
class Person(val name: String) {
companion object: JSONFactory{
override fun fromJSON(jsonText: String): Person = ....
}
}
fun loadFromText<T>(factory:JSONFactory<T>): T {
...
}
fun main(args: Array<String>) {
loadFromText(Person)
}
위 예제처럼 companion object가 특정 interface를 구현할 수도 있고, 이 interface를 넘겨줄때는 외부 class 이름을 사용합니다.
자바에서 호출시 Companion을 붙여서 사용해야 합니다.
Person.Companion.fromJSON("....");
만약 companion에 이름이 있다면 해당 이름이 대신해서 쓰입니다.
자바에서 companion object로 명명된 함수나 property를 static처럼 호출해서 쓰고 싶다면 @JvmStatic 이나 @JvmField 어노테이션을 함수나, property 앞에 붙여야 합니다.
또한 companion object에 대해서 Extension function을 만들어 추가할 수도 있습니다만, 자세한건 책을 사서 확인하시면 됩니다~
4.4.4 익명클래스의 구현
interface ClickListener {
fun onClick()
}
fun main(args: Array) {
setClickAction(object : ClickListener {
override fun onClick() {
println("clicked!!!")
}
}
)
}
fun setClickAction(clickListener: ClickListener) {
clickListener.onClick()
}
여기서 익명 클래스는 singleton이 아닙니다. 따라서 호출시 매번 객체가 생성된다는 점과 익명클래스 내에서는 외부 클래스의 변수에 접근하여 값을 수정할 수도 있습니다.(자바와는 다른점입니다. 자바는 익명클래스에서 접근시 무조건 final이어야만 합니다.
'개발이야기 > Kotlin' 카테고리의 다른 글
[Kotlin] 코틀린 람다 #2 Collection API - filter, map, groupby, flatmap, sequence, find, any, all, count (2) | 2018.04.25 |
---|---|
[Kotlin] 코틀린 람다 #1 - 기본 문법 (5) | 2018.04.25 |
[kotlin] 코틀린 데이터 클래스와 위임 (0) | 2018.04.22 |
[Kotlin] 코틀린 class 생성자와 property (0) | 2018.04.20 |
[Kotlin] 코틀린 삼중따옴표, 정규식, 문자열, 중첩함수 , 확장함수 (2) | 2018.04.18 |