[kotlin] 클래스와 객체 다루기3

maxxyoung·2023년 3월 19일

객체

객체 선언

  • 객체 선언이란 클래스와 상수를 합친 것
  • 코틀린은 어떤 클래스에 인스턴스가 오직 하나만 존재하게 보장하는 싱글턴 패턴을 내장
  • 코틀린에서는 클래스와 비슷한 방법으로 싱글턴을 선언하는데 object라는 키워드 사용
object Application {
	val name = "My Application"
    
    override fun toString() = name
    
    fun exit(){}
}
  • 이러한 객체 선언은 클래스를 정의하는 동시에 클래스 인스턴스를 정의하는 것이기도 함
  • 값, 타입으로 모두 사용가능
  • 객체 정의는 스레드 세이프
    • 컴파일러는 실행되는 여러 스레드에서 싱글톤에 접근하더라도 오직 한 인스턴스만 공유되고 초기화 코드도 단 한 번만 실행 되도록 보장
  • 초기화는 싱글턴 클래스가 실제 로딩되는 시점까지 지연
    • 보통은 프로그램이 객체 인스턴스에 처음 접근할 때 초기화 이루어짐
  • 객체 선언도 멤버 함수, 프로퍼티, 초기화 블록 포함할 수 있지만, 객체 인스턴스는 항상 암시적으로 만들어지기 때문에 주생성자, 부생성자가 의미가 없고 객체에 존재하지 않음
  • 객체 본문에 들어있는 클래스에 inner붙을 수 없음
import Application.exit

fun main() {
	println(Application.name)
    exit()
}
  • 최상위 선언들과 마찬가지로, 객체 멤버를 임포트해서 간단한 이름만 사용해 참조 가능
  • 객체의 모든 멤버가 필요할 때 임포트 문으로 임포트 불가능(import Application.* 안됨)
    • 객체 정의 안에는 다른 클래스 정의와 같이 toString() 이나 equals()와 같은 공통 메서드 정의가 들어있기 때문
  • 자바는 정적 메서드들을 모아 놓은 util 클래스는 만들어 사용하지만 코틀린에서는 권장되지 않음
    • 코틀린 클래스에서는 정적 메서드 정의할 수 없음
    • 코틀린은 자바와 달리 최상위 선언을 패키지 안에 함께 모아둘 수 있으므로 불필요하게 유틸리티 클래스를 선언해야할 필요 없음

동반 객체

  • 내포된 클래스와 마찬가지로 내포 객체도 인스턴스가 생기면 자신을 둘러싼 클래스의 비공개 멤버에 접근할 수 있음
    • 이러한 특성을 가지고 팩토리 디자인 패턴을 쉽게 구현하는 경우 유용하게 활용가능
      ex) 생성자를직접 생성하고 싶지 않을 때
      import Application.Companion.create  
      class Application private contructor(val name: String) {
      	companion object {
        	fun create(args: Array<String>): Application? {
            	val name = args.firstOrNull() ?: return null
                return Applicaiton(name)
            }
        }
      }
      fun main(args: Array<String>) {
      	val app = create(args) ?: return
      	println("Application started: ${app.name}")
      }
      생성자를 비공개로 지정해 클래스 외부에서 사용할 수 없게 한 다음, 내포된 객체에 팩토리 메서드 역할을 하는 함수를 정의하고 그 함수 안에서 필요에 따라 객체의 생성자를 호출
  • 동반 객체의 경우 정의에서 이름을 아예 생략할 수 있음(이 방식 권장)
    • 이름 생략한 경우 컴파일러는 동반 객체의 디폴트 이름을 Companion으로 가정
  • 클래스에 동반 객체가 둘 이상 있을 수 없음
  • 코틀린 동반 객체의 문맥은 객체 인스턴스
    • 코틀린 동반 객체는 다른 상위 타입을 상속할 수도 있고 일반 객체 처럼 여기저기 전달 될 수 있음
    • 자바의 static 초기화 블록처럼 동반 객체 안에서도 init 블록을 사용할 수 있음

객체 식

  • 객체 식은 자바 익명 클래스와 아주 비슷
  • 객체 식도 식이므로 앞의 예제처럼 객체 식이 만들어내는 값을 변수에 대입할 수 있음
  • 객체를 함수 안에 정의할 수는 없음
    • 객체 선언이 싱글턴을 표현하지만 지역 객체들은 자신을 둘러싼 바깥 함수가 호출될 때마다 매번 다시 생성돼야 하기 때문
fun main() {
  fun minPoint(xRange: Integer, yRange: IntRange) = object {
    val x = (xRange.first + yRange.last)/2
    val y = (yRange.first + XRange.last)/2
  }
  val midPoint = minPoint(1..5, 2..6)
  println("${minPoint.x}, ${minPoint.y}")
  }
  • 객체 식이 반환하는 타입은 익명 객체 타입이며, 이런 타입은 하나만 존재(멤버가 모두 완전히 똑같은 두 객체 식이 있다고 해도, 둘의 타입은 서로 다름)

출처

  • 코틀린 완벽 가이드
profile
오직 나만을 위한 글. 틀린 부분 말씀해 주시면 감사드립니다.

0개의 댓글