코틀린에서 클래스를 다루는 방법


1. 클래스와 프로퍼티
프로퍼티 = 필드 + getter + setter
코틀린에서는 필드만 만들면 getter, setter를 자동으로 만들어준다.

(주/부)생성자 및 초기화 init 클래스 사용

fun main() {
    Person()
}

class Person(
    val name: String,
    val age: Int
) {
    init {
        if (age <= 0) {
            throw IllegalArgumentException("나이는 ${age}일 수 없습니다.")
        }
        println("초기화 블록")
    }

    constructor(name: String): this(name, 1) {
        println("첫 번째 부생성자")
    }

    constructor(): this("홍길동") {
        println("두 번째 부생성자")
    }
}

주 생성자는 class 클래스명(변수) 와 같이 작성하고, init에 초기화와 부 생성자(constructor)를 통해서 생성자 오버로딩이 가능합니다. 부 생성자에서는 꼭 주 생성자를 호출해주어야 합니다.

커스텀 getter, setter

fun isAdult(): Boolean {
	return this.age >= 20
}
val isAdult: Boolean
	get() = this.age >= 20
val isAdult: Boolean
	get() {
    	return this.age >= 20
        }

isAdult는 성인인지 아닌지를 판별하는 함수 혹은 프로퍼티인데요
첫번째 함수처럼 함수로 생성해서 하는게 일반적이지만 프로퍼티로 생성해서 사용해도 괜찮습니다.

backing field

backing field는 자신을 가르키는 필드로 무한루프를 막기 위한 예약어 입니다. 예제를 살펴 보겠습니다.

val name String = name
	get() = field.uppercase()

위 예제는 이름을 요청 받았을 때 알파벳 대문자로 만들어서 반환하게 됩니다. 저기서 field 부분이 이제 name을 대체합니다. 여기서 의문점은 field말고 그냥 name을 사용하면 되지 않냐 이겁니다. 하지만 name에서 getter를 호출하면 그안에 네임이 있고 그안에서 getter를 호출하고 그안에 name이 있는 무한 반복이 되기 때문에 backing field를 사용하게 됩니다

정리

  • 실제 메모리에 존재하는 것과 무관하게 custom getter와 custom setter를 만들 수 있다.
  • custom getter, custom setter에서 무한루프를 막기 위해 field라는 키워드를 사용한다.
  • 이를 backing field 라고 부른다.

코틀린에서 상속을 다루는 방법


class Cat(
	species: String
) : Animal(species, 4) {
	override fun move() {
    	println("고양이가 사뿐 사뿐 걸어가~")
    }
}

위 코드는 고양이가 animal이라는 부모 클래스를 상속 받고 있는 모습입니다.
상속 받을 시 주의사항

  • : 앞에 무조건 공백을 넣고 부모 클래스를 상속 받아야 됩니다.
  • 상속 받음을 나타냄과 동시에 생성자를 호출해야 한다.
  • 메소드가 존재하면 override를 필수적으로 붙여주어야 한다. override에는 어노테이션이 없는 지시어이다.

프로퍼티를 오버라이드 하기 위해서는 open을 붙여주어야 된다.

abstract class Animal(
	protected val species: String,
    protected open val legCount: Int
) {
	abstract fun move()
}
  • 추상 프로퍼티가 아니라면, 상속받을 때 open을 붙여야 한다.
  1. final: override를 할 수 없게 한다. default로 보이지 않게 존재한다. 디폴트로 final이 붙어있다.
  2. open: override를 열어 준다.
  3. abstract: 반드시 override 해야 한다.
  4. override: 상위 타입을 오버라이드 하고 있다.
  • 상속 또는 구현을 할 때에 : 을 사용해야 한다.
  • 상위 클래스 상속을 구현할 때 생성자를 반드시 호출해야 한다.
  • override를 필수로 붙여야 한다.
  • 추상 멤버가 아니면 기본적으로 오버라이드가 불가능하다.
  • open을 사용해주어야 한다.
  • 상위 클래스의 생성자 또는 초기화 블록에서 open 프로퍼티를 사용하면 얘기치 못한 버그가 생길 수 있다.

코틀린에서 접근 제어를 다루는 방법


  • Kotlin에서 패키지는 namespace 관리용이기 때문에 protected는 의미가 달라졌다.
  • Kotlin에서는 default가 사라지고, 모듈간의 접근을 통제하는 internal이 새로 생겼다.
  • 생성자에 접근 지시어를 붙일 때는 constructor를 명시적으로 써주어야 한다.
  • 유틸성 함수를 만들 때는 파일 최상단을 이용하면 편리하다.
  • 프로퍼티의 custom setter에 접근 지시어를 붙일 수 있다.
  • Java에서 Kotlin 코드를 사용할 때 internal과 protected는 주의해야 한다.

코틀린에서 object 키워드를 다루는 방법


  • Java의 static 변수와 함수를 만드려면, Kotlin에서는 companion object를 사용해야 한다.
  • companion object도 하나의 객체로 간주되기 때문에 이름을 붙일 수 있고, 다른 타입을 상속받을 수도 있다.
  • Kotlin에서 싱글톤 클래스를 만들 때 object 키워드를 사용한다.
  • Kotlin에서 익명 클래스를 만들 때 object: 타입을 사용한다.
    익명 클래스 예제
fun main() {
	moveSomething(object : Movable {
    	override fun move() {
        	println("움직인다")
        }
        
       override fun fly() {
       		println("난다~~")
       }
   })
    

코틀린에서 중첩 클래스를 다루는 방법


  • 코틀린에서는 내부 클래스는 외부 클래스를 참조할 경우 메모리 누수가 발생할 수 있기 때문에 static 을 사용한 내부 클래스를 만드는 것을 권장한다.

권장하지 않는 타입의 예제


class House(
    var address: String,
) {
    
    var livingRoom = this.LivingRoom(10.0)
    
    inner class LivingRoom(
        private var area: Double,
    ) {
        val address: String
            get() = this@House.address
    }
}

정리

  • 코틀린에서는 기본적으로 바깥 클래스 참조하지 않는다.
  • 바깥 클래스를 참조하고 싶다면 inner 키워드를 추가해야한다.
  • 코틀린에서는 이러한 가이드를 따르기 위해
  • 클래스 안에 기본 클래스를 사용하면 바깥 클래스에 대한 참조가 없고
  • 바깥 클래스를 참조하고 싶다면, inner 키워드를 붙여야 한다.
  • 코틀린 inner class에서 바깥 클래스를 참조하려면 this@바깥클래스를 사용해야 한다.
  • 클래스 안에 클래스가 있는 경우 종류는 두 가지 였다.
  • (Java기준) static을 사용하는 클래스
  • (Java기준) static을 사용하지 않는 클래스

코틀린에서 다양한 클래스를 다루는 방법


  • Kotlin의 Data class를 사용하면 equals, hashCode, toString을 자동으로 만들어준다.
  • Kotlin의 Enum Class는 Java의 Enum Class와 동일하지만, when과 함께 사용함으로써 큰 장점을 갖게 도니다.
  • Enum Class보다 유연하지만, 하위 클래스를 제한하는 Sealed Class 역시 when과 함께 주로 사용된다.
  • Sealed의 하위 클래스는 같은 패키지에 있어야 한다.
profile
개발에 재미를 느끼며 꾸준히 성장하는 개발자 김종완 입니다.

0개의 댓글