BackEnd/Kotlin

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

hanseom 2024. 3. 3. 06:00
반응형
  1. 클래스와 프로퍼티
  2. 생성자와 init
  3. 커스텀 getter, setter

 

클래스와 프로퍼티

  • 프로퍼티(property) = 필드(field) + getter + setter

 

  다음은 개명이 불가능한 Java 클래스입니다.

public class JavaPerson {

  private final String name;
  private int age;

  public JavaPerson(String name, int age) {
    this.name = name;
    this.age = age;
  }

  public String getName() {
    return name;
  }

  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

}

 

  Kotlin으로 구현하면 다음과 같습니다. Kotlin에서는 필드만 만들면 getter, setter를 자동으로 만들어 줍니다. 그러므로 Kotlin에서는 프로퍼티라고 부릅니다.

public class Person constructor(name: String, age: Int) {
  val name = name
  var age = age
}
  • 접근 지시어, public은 생략 가능합니다.
  • constructor는 생략할 수 있습니다.
  • 클래스의 필드 선언과 생성자를 동시에 선언할 수 있습니다.
  • 클래스의 body에 아무 것도 없다면 생략 가능합니다.

  그러므로, 다음과 같이 간결하게 구현할 수 있습니다. 

class Person(
  val name: String,
  var age: Int
)

 

  getter, setter에 대한 호출은 .필드를 사용합니다. Kotlin에서 Java 클래스를 사용할 경우에도 .필드로 getter, setter를 사용합니다.

val person = Person("Kotlin", 100)
println(person.name) // getter
person.age = 10      // setter
println(person.age)

 

생성자와 init

  다음은 클래스가 생성되는 시점에 나이를 검증하는 Java 코드입니다.

  public JavaPerson(String name, int age) {
    if (age <= 0) {
      throw new IllegalArgumentException(String.format("나이는 %s일 수 없습니다", age));
    }
    this.name = name;
    this.age = age;
  }

 

  Kotlin으로 구현하면 다음과 같습니다.

class Person(
  val name: String,
  var age: Int
) {
  init {
    if (age <= 0) {
      throw IllegalArgumentException("나이는 ${age}일 수 없습니다.")
    }
  }
}
  • init(초기화 블록):  클래스가 초기화되는 시점에 한 번 호출되는 블록입니다. 값을 적절히 만들어 주거나 validation 로직을 넣는 용도로 사용됩니다.

 

  다음은 새로운 생성자를 추가한 Java 코드입니다.

  public JavaPerson(String name, int age) {
    if (age <= 0) {
      throw new IllegalArgumentException(String.format("나이는 %s일 수 없습니다", age));
    }
    this.name = name;
    this.age = age;
  }

  public JavaPerson(String name) {
    this(name, 1);
  }

 

  Kotlin에서 새로운 생성자는 constructor 키워드와 함께 만들어져야 합니다.

class Person(
  val name: String,
  var age: Int
) {                                          // primary constructor
  init {
    if (age <= 0) {
      throw IllegalArgumentException("나이는 ${age}일 수 없습니다.")
    }
    println("init block")
  }
  
  constructor(name: String) : this(name, 1) { // secondary constructor 
    println("secondary constructor")
  }
}
  • constructor(파라미터)로 생성자를 추가합니다.
  • 클래스를 만들 때 함께 만들었던 생성자를 주생성자(primary constructor)라고 합니다.
  • 주생성자는 반드시 존재해야 합니다. 단, 주생성자에 파라미터가 하나도 없다면 생략 가능합니다.
  • 아래 있는 생성자를 부생성자(secondary constructor)라고 합니다. 부생성자는 있을 수도 있고 없을 수도 있습니다.
  • 부생성자는 최종적으로 주생성자를 this로 호출해야 합니다.
  • 부생성자는 body를 가질 수 있습니다.
  • 본문은 역순으로 실행됩니다. 즉, 부생성자를 통해 인스턴스를 생성하면 초기화 블록의 body가 먼저 호출됩니다.

  Kotlin에서는 다음과 같이 부생성자보다는 default parameter를 권장합니다. 또한, Converting과 같은 경우도 부생성자를 사용할 수 있지만, 그보다 정적 팩토리 메서드 사용을 권장합니다.

class Person(
  val name: String = "Kotlin",
  var age: Int = 1,
) {                                          // primary constructor
  init {
    if (age <= 0) {
      throw IllegalArgumentException("나이는 ${age}일 수 없습니다.")
    }
  }
}

 

커스텀 getter, setter

  다음은 성인인지 확인하는 Java 코드입니다.

  public boolean isAdult() {
    return this.age >= 20;
  }

 

  Kotlin에서는 Java와 같이 함수로 구현할 수도 있고, 프로퍼티로도 구현할 수 있습니다.

    // Function
    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할 때 무조건 대문자로 바꾸어 주는 코드입니다.

class Person(
    name: String,
    var age: Int
) {
    val name = name
        get() = field.uppercase()
}
  • field: 자기 자신을 가리키는 예약어입니다. 보이지 않는 field라고 해서 backing field라고 부릅니다.

 

  다음은 Custom setter를 사용한 예제 코드입니다. name을 set할 때 무조건 대문자로 바꾸는 코드입니다.

class Person(
    name: String,
    var age: Int
) {
    var name = name
        set(value) {
            field = value.uppercase()
        }
}

 

감사합니다.

반응형