코틀린 & Java/코틀린인액션

[Kotlin] 클래스, 객체, 인터페이스에 대해 알아보자 (2)

코딩하는후운 2024. 3. 18. 13:45
반응형

Kotlin 클래스, 객체, 인터페이스

Any class

  • The root of the Kotlin class hierarchy. Every Kotlin class has Any  as a superclass.
  • open function으로 equals, hashCode, toString을 제공

equals, hashCode, toString

  • 코틀린 컴파일러가 보이지 않는 곳에서 생성해 준다.

문자열 표현: toString()

  • 인스턴스의 문자열 표현 제공
  • 디버깅과 로깅 시 사용

객체의 동등성: equals()

자바 equals

  • 객체의 동등성

자바 ‘==’

  • 원시 타입 에서는 값 비교
  • 참조 타입 에서는 주소 비교

코틀린 ‘==’

  • 내부적으로 equals를 호출
  • 객체의 동등성
  • 값 비교

코틀린 ‘===’

  • 주소 비교
  • 참조 동일성
val client1 = Client("도과장", 11)
val client2 = Client("도과장", 11)

println(client1 == client2)
>> false

override fun equals(other: Any?): Boolean {
		return other.name == this.name.....
	  값 비교 로직...
}
>> true

해시 컨테이너: hashCode()

val processed = hashSetOf(Client("최대리", 11))
println(processed.contains(Client("최대리", 11)))
>> false

override fun hashCode(): Int = name.hashCode() * 31 + postalCode

JVM 언어에서는 “equals()가 true를 반환하는 두 객체는 반드시 같은 hashCode()를 반환해야 한다”

HashSet의 원소 비교는 객체의 해시 코드를 비교 후 실제 값 비교

두 Client 인스턴스의 해시코드가 다름

why 31 ?

Why does Java's hashCode() in String use 31 as a multiplier?

data class

클래스를 데이터 저장하는 역할만 수행한다면 위 3가지 함수를 반드시 override 해야함.

코틀린은 data class로 만들면 컴파일러가 자동으로 만들어 줌.

data class Client(val name: String, val postalCode: Int)
  • 인스턴스 간 비교를 위한 equals
  • 해시 컨테이너의 키로 사용할 수 있는 hashCode
  • 클래스의 필드 선언 순서대로 표시하는 문자열 표현을 만들어주는 toString

data class의 프로퍼티를 var로 써도 되지만 val로 불변 클래스로 만들기를 권장.

불변에 대한 장점은 1장에서 설명.

copy()

data class 불변으로 권장하는 대신 copy 메소드로 편의를 제공

  • 객체 복사하면서 일부 프로퍼티를 변경할 수 있음
  • 객체를 메모리상에서 바꾸는 대신 복사본을 만드는 편이 나음

by

대규모 객체지향 시스템 설계 시, 시스템을 취약하게 만드는 문제 ⇒ 구현, 상속

상속을 허용하지 않는 클래스에 새로운 동작 추가 ⇒ 데코레이터 패턴

(p.179) 준비 코드가 상당히 많다 ⇒ by 키워드를 통해 위임해 보자

(p.180 상단) Collection<T> by innerList

위임 했지만 일부 동작을 변경하고 싶다? ⇒ override

Object

클래스를 정의하면서 동시에 인스턴스를 생성

  • 싱글턴을 정의하는 방법 중 하나
  • companion object 어떤 클래스와 관련 있는 메소드와 팩토리 메소드를 담을 때 쓰임
  • 객체 식은 자바의 무명 내부 클래스 대신 쓰임

싱글턴 쉽게 만들기

코틀린은 객체 선언 기능을 통해 싱글턴을 언어에서 기본 지원

객체 선언은 클래스 선언과 단일 인스턴스의 선언을 합친 것

❗object는 생성자를 선언할 수 없다.

자바에서 코틀린 object 호출하려면 INSTANCE 필드를 통하면 된다.

CaseInsensitiveFileComparator.INSTANCE.compare(file1, file2);

companion object

코틀린은 static 키워드 지원하지 않음.

그 대신 최상위 함수, companion object가 있음.

❗ 최상위 함수는 클래스 내부의 private 멤버를 호출할 수 없음.

팩토리 메소드 패턴으로 companion object를 쓸 수 있음. (p.187, 188)

팩토리 메소드 패턴(Factory Method Pattern)은 객체를 생성하기 위해 인터페이스를 만듭니다. 어떤 클래스의 인스턴스를 만들지를 서브클래스에서 결정하도록 합니다. 팩토리 메소드를 이용하면 인스턴스를 만드는 일을 서브클래스로 미룰 수 있습니다.

무엇보다 싱글턴 만들때 사용한다.

이름을 지어줄 수 있다.

companion object Loader {
	fun fromJSON() ...
}

이름을 지정하지 않으면? ⇒ 자동으로 Companion이 됨.

자바에서 접근 한다면? ⇒ Person.Companion.fromJSON(”…”)

인터페이스 구현도 가능! (p.190)

자바에서 사용하기 위해 코틀린 클래스의 멤버를 static 멤버로 만들어야 할 땐 ⇒ @JvmStatic

정적 필드가 필요하다면 ⇒ @JvmField

동반 객체 확장

class Person(val name: String) {
	companion object {}
}

fun Person.Companion.fromJSON(): Persion { ... }

val p = Person.fromJSON()

이렇게 쓸 수도 있다.

anonymous object

Listener에서 많이 써왔다.

window.addMouseListener {
	object : Adapter() {
		override fun click() { ... }
	}
}

SAM ( Single Abstract Method )

  • 추상 메소드가 하나만 있는 인터페이스
public interface OnClickListener {
        void onClick(View v);
}

button.setOnClickListener{ view -> ... }
반응형