Language/kotlin

클래스 다루기

kimjingyu 2023. 5. 19. 17:46
728x90

클래스와 프로퍼티

class KotlinPerson constructor(name: String, age: Int){
    val name = name
    val age = age
}
  • 코틀린에서는 필드만 만들면 getter와 setter를 자동으로 만들어준다.
    • property = field + getter + setter
  • constructor는 생략할 수 있다.
class KotlinPerson(
    name: String, 
    age: Int
){
    val name = name
    val age = age
}
  • 클래스의 필드 선언과 생성자를 동시에 선언할 수 있다.
    • 생성자: constructor(name: String, age: Int)
    • 필드
      • val name = name
      • val age = age
  • .필드 를 통해서 getter와 setter를 바로 호출한다.
    • 자바 클래스, 코틀린 클래스 상관없음.
// kotlin class 이용
val kotlinPerson = KotlinPerson("kotlinUser", 100)
// getter
println(kotlinPerson.name)
// setter
kotlinPerson.age = 10
println("kotlinPerson.age = ${kotlinPerson.age}")

// java class 이용
val javaPerson = JavaPerson("javaUser", 30)
// getter
println(javaPerson.name)
// setter
javaPerson.age = 50
println("javaPerson.age = ${javaPerson.age}")

생성자와 init

  • 클래스가 생성되는 시점에 나이 검증
    • 자바: 생성자에 검증 부분을 넣어준다.
    • 코틀린: init(초기화) 블록을 이용하면 생성자가 호출되는 시점에 호출된다.
      • init: 값을 적절히 만들어주거나, validatio하는 로직
init {
    if (age <= 0) {
        throw IllegalArgumentException("나이(${age})는 1 이상이어야 합니다.")
    }
}
  • 최초로 태어나는 아기는 무조건 1살이다. -> 생성자를 하나 더 만든다.
    • 자바: this를 사용해서 나이가 무조건 1살인 생성자를 하나 더 만든다.
    • 코틀린: constructor(parameter)로 생성자를 추가하고, : this(name, 1)로 주생성자(primary constructor)를 호출한다.
      • 주생성자(primary constructor)
        • 반드시 존재해야 한다.
        • 단, 주생성자에 파라미터가 하나도 없다면 생략이 가능하다.
      • 부생성자(secondary constructor)
        • 있을수도 있고, 없을수도 있다.
        • 최종적으로 주생성자를 this로 호출해야 한다.
        • body를 가질 수 있다.
// 부생성자 사용
class KotlinPerson1(
    // 주생성자
    name: String,
    age: Int
){
    val name = name
    var age = age

    init {
        if (age <= 0) {
            throw IllegalArgumentException("나이(${age})는 1 이상이어야 합니다.")
        }
        println("초기화 블록")
    }

    // 부생성자 - 최초로 태어나는 아기는 무조건 1살이다.
    constructor(name: String): this(name, 1){
        println("부생성자1")
    }

    constructor() : this("user"){
        println("부생성자2")
    }

    override fun toString() = "KotlinPerson(name=${name}, age=${age})"
}
  • BUT, 부생성자보다는 default parameter를 권장한다.
  • Converting과 같은 경우는 부생성자를 사용할 수 있지만, 그보다는 정적 팩토리 메서드를 추천한다.
// default parameter 사용
class KotlinPerson2(
    val name: String = "user",
    var age: Int = 100
) {
    init {
        if (age <= 0) {
            throw IllegalArgumentException("나이(${age})는 1 이상이어야 합니다.")
        }
    }

    override fun toString() = "KotlinPerson(name=${name}, age=${age})"
}

커스텀 getter, setter

  • 모두 동일한 기능이고, 표현 방법만 다르다.
fun isAdult(): Boolean{
   return this.age >= 20
}
  • 객체의 속성과 관련된 기능이라면, custom getter를 사용한다.
val isAdult: Boolean
	get() = this.age >= 20
val isAdult: Boolean
    get() {
        return this.age >= 20
    }
  • custom getter를 사용하면, 자기 자신을 변형해 줄 수 있다.
// name 을 get 할 때, 무조건 대문자로 바꾸기
val name: String = name
    get() = field.uppercase()
  • 주생성자에서 받은 name을 불변 프로퍼티 name에 바로 대입시켜 준다.
  • name에 대한 custom getter를 만들 때, field를 사용한다.
    • get() = name.uppercase() 이면,
    • name은 name에 대한 getter를 호출하니까 다시 get을 부른다.
    • getter 안에는 다시 name이 있으므로, 무한루프가 발생한다.

backing field

  • 무한루프를 막기 위한 예약어로 자기 자신을 가리킨다.
  • 실무에서는 custom getter에서 backing field를 사용하는 경우는 드물다.
  • 밖에서 볼 때, 우리가 원하는 요구사항을 달성하는 프로퍼티가 하나 더 있는 것처럼 보여줄 수 있기 때문
val upperCaseName: String
    get() = this.name.uppercase()
  • name을 set할 때, 무조건 대문자로 바꿔주기
// name 을 set 할 때, 무조건 대문자로 바꿔주기
var name: String = name
    set(value) {
        field = value.uppercase()
    }
728x90