매일 한줄 코딩

#10. 코틀린 오브젝트 키워드 본문

develop/kotlin

#10. 코틀린 오브젝트 키워드

ShipJH 2022. 6. 6. 23:33
8. Properties and Fields

 

10. 오브젝트 키워드 - Object Expressions and Declarations

 

 


 

1. 오브젝트 - Object

👉 Object 용도

  • 어떤 class에서 조금 변경된 객체를 생성 할 때
  • 새로운 subclass의 명시적인 선언 없이 객체 생성

 

👉 3가지 요소.

  • Object Expressions
    • Java익명 객체
  • Object Declarations
    • 싱글턴
  • Compaion Object
    • 싱글턴 + Class method (static 팩토리메서드.. 등과 같은개념)
    → 그냥 static을 사용하면되지 왜 굳이?
  • 코틀린에서는 정적(static) 변수 혹은 메소드가 없다→ 대신 패키지 내에 함수를 선언하여 사용할 수 있다.
  • → 코틀린에서 권고하는것은 같은 패키지레벨에서 함수를 써라.

 

 


 

 

2. 객체 표현식 (Object Expressions)

  • java에서는 익명 내부 클래스를 사용하여 처리하였다. 단, 코틀린에서는 Object expressions를 사용한다.
// java
btn.setOnclickListener( new OnclickListstener() {
	public void onClick(View v) {
		//...
	}
}


//kotlin
window.addMouseListener(object : MouseAdapter() {
	override fun mouseClicked(e: MouseEvent { ... }
	override fun mouseEntered(e: MouseEvent { ... }
})

위처럼 익명 클래스(new) 를 사용하지않고, object 키워드를 이용하여 구현한다.

 

이해하기 쉬운 예시

class MyRun : Runnable {
    override fun run() {
        println("hello ~ ")
    }
}

fun main(args: Array<String>) {
    val t = Thread(MyRun())
    t.start()
}

//콘솔 출력 : hello ~

위에서 보면,

val t = Thread(MyRun()) 할때 MyRun 클래스를 정의하지 않고 그냥 Runnable의 run()만 조금 바꿔서 만들 고 싶을때가 있다.

아래와 같이 하면된다.

class MyRun : Runnable {
    override fun run() {
        println("hello ~ ")
    }
}

fun main(args: Array<String>) {
    val t = Thread(object : Runnable {
        override fun run() {
            println("hello ~ ")
        }
    })
    t.start()
}

//콘솔 출력 : hello ~

MyRun()을 제거하고 위와같이 object 명령어를 쓰고 재정의하면 된다.

 

람다식을 사용하면 더 간단해진다

fun main(args: Array<String>) {
    val t = Thread(Runnable {
            println("hello ~ ")
    })
    t.start()
}
//콘솔 출력 : hello ~
//Runnable 도 지워도 됨.

 

 

 

2-1. 객체 표현식 상속

  • 슈퍼타입의 생성자가 있는 경우, 반드시 값을 전달 해 주어야 함
  • 슈퍼타입이 여러 개인 경우 콜론(:) 뒤에 콤마(,) 로 구분해서 명시 해주면 됨.
open class A(x: Int) {
	public open val y: Int = x
}

interface B { ... }

val ab: A = object : A(1), B { //A에 반드시 값을 전달하였고, 슈퍼타입이 여러개 쓸것이니 콤마를 씀
	override val y = 15
}

 

 

2-2. 객체 표현식 상속 없는 경우

  • 특별히 상속받은 슈퍼타입이 없는 경우, 간단하게 작성이 가능하다
fun main(args: Array<String>) {
    val data = object {
        var x = 100
        var y = 200
    }
    println("${data.x}, ${data.y}")
}

// 콘솔출력 : 100, 200

 

  • 아무것도 없어도된다. 단 바디는 있어야된다.
fun main(args: Array<String>) {
	val data = object { }
	println(data)
}

 

 

2-3. 객체 표현식 제약 사항

  • 익명객체가 local이나 private로 선언될 때만 type으로 사용 될 수 있다.
  • 익명객체가 public funcion이나 public property에서 리턴 되는 경우에는 익명객체의 슈퍼타입으로 동작된다. 이런 경우에는 익명객체에 추가된 멤버에 접근이 불가능하다.

 

class C {
	private fun foo() = object { val x: String = "X" }
	fun publicFoo() = object { val x: String = "X" }

	fun bar() {
		val x1 = foo().x       // 가능
		val x2 = publicFoo().x // error
	}
}

 

 

2-4. 객체 표현식 특징

  • 익명객체의 코드는 enclosiong scope의 변수를 접근 할 수 있음
  • java와 다르게 final variables 제약조건 없다.
fun count(...) {
	var count = 0

	clickClass.addClick(object: myClick() {
		override fun click() {
			count++ // count에 접근이 가능!!
		}
	})
}

 

 

 


3. 객체 선언 (Object declarations)

 

  • 객체선언 용도싱글턴 패턴을 코틀린에서는 object declarations를 이용하여 만들 수 있다.
object DataProvicderManager {
	fun registDataProvider(provider: DataProvider) {
		//...
	}

	val allDataProviders: Collection<DataProvider>
		get() = //....
}

 

 

3-1. 객체 선언 문법

  • object 키워드 뒤에 항상 이름이 있어야함
  • object declaration(객체선언)은 object expression(객체표현식)이 아니므로, 할당 구문의 우측에 사용 될 수 없다.
object DataProviderManager {
	fun registerDataProvider(provider: DataProvider) { }
	val allDataProviders: Collection<DataProvider>
}
  • object declaration 의 객체를 참조하려면, 해당 이름으로 직접접근하면 된다.
DataProviderManager.registerDataProvider(...)

쉬운설명

object CountManager {
    var count = 0
}

fun main(args: Array<String>) {
    CountManager.count++
    println(CountManager.count) //1
    CountManager.count++
    println(CountManager.count) //2
    CountManager.count++
    println(CountManager.count) //3 
}

 

 

  • 슈퍼타입을 가질 수 있음 (상속가능)
object 이름: 상속객체() {
	// ...
}

 

 


 

4. 동반자 객체 (Companion Object)

  • 클래스 내부의 object declaration은 companion 키워드를 붙일 수 있다.
  • companion object의 멤버 클래스 이름을 통해서 호출 할 수 있다
class MyClass {
//companion만 빼면 객체선언식이나 다름없다. 
	companion object Factory { 
		fun create(): MyClass = MyClass()	
	}
}

//MyClass.Factory.create()로 호출해야되는데, companion object가 되면 바로 호출가능
//자바의 static 메서드를 커버할 수 있다.
//멤버 클래스 이름을 통해서 호출
val instance = MyClass.create()

 

 

  • companion object의 이름은 생략 할 수 있다.
  • 생략할 경우 [class name].Companion으로 객체의 접근이 가능하다
class MyClass {
	companion object {
		//...
	}
}

val x = MyClass.Companion

 

 


 

 

5. 차이점 & 특징 정리.

  • Object Expressions : 즉시 초기화 되고 실행된다.
  • Object Declarations : 나중에 초기화 된다.(최초 접근시)
    • 처음로드 될때 생성되는게 아니기때문에 맘놓고 사용
    • 여러번 호출해도 최초 접근할때 생성된거 1개만 생성 → 싱글턴
  • Companion Object : 클래스가 로드 될 때 초기화 된다. java staitc initializer와 같다.

 

 

 

 

 

 

 

 

 

 

 

 

 

Comments