본문 바로가기
  • 개발하는 곰돌이
Programming Language/Kotlin & Java

Kotlin 기본 문법 10 : 커스텀 getter와 setter

by 개발하는 곰돌이 2022. 12. 22.

목차

    개요

    Kotlin의 클래스 역시 Java와 마찬가지로 각 필드에 대한 getter와 setter가 존재한다. 이번 포스트에서는 Kotlin 클래스의 기본적인 getter와 setter 및 Kotlin 클래스의 커스텀 getter와 setter에 대해 정리한다.


    Kotlin 클래스의 기본 getter와 setter

    Kotlin에서 클래스를 작성하는 방법은 Kotlin 기본 문법 6 : 클래스와 접근 지정자 포스트에서 이미 다룬바가 있다. Kotlin 클래스의 필드는 기본적으로 Java와 달리 별도의 getter, setter 메소드로 접근하지 않는다. 대신 Kotlin에서는 클래스의 생성자를 작성하면 필드의 종류(val, var)에 따라 자동으로 getter와 setter를 생성해주고, 일반적으로 필드에 접근하듯이 객체명.필드명을 사용하면 자동으로 getter와 setter를 호출하게 되므로 별도의 getter와 setter를 작성할 필요가 없다.

    생성자만 작성한 Kotlin의 Person 클래스를 Java코드로 디컴파일하면 자동으로 getter와 setter가 생성된다.

    위 사진을 보면 val로 설정한 name은 getter만 생성되었고, var로 작성한 age는 getter와 setter가 모두 생성된 것을 볼 수 있다.


    커스텀 getter

    커스텀 getter는 기본 getter 외에 추가적인 getter가 필요할 때 사용한다. 예를 들어 직사각형을 나타내는 Rectangle 클래스가 있다.

    class Rectangle(var width: Int, var height: Int)

    이 Rectangle 클래스에서 직사각형의 넓이나 대각선의 길이를 구하고 싶다면 클래스 내부에 넓이를 나타내는 필드를 새로 작성하면 된다고 생각할 수 있다.

    class Rectangle(var width: Int, var height: Int) {
        val area = width * height
    }

    하지만 이 방법은 직접 사용해보면 아래와 같은 문제가 있다.

    fun main() {
        val rectangle = Rectangle(3, 5)
        println(rectangle.area)
        rectangle.width = 4
        println(rectangle.area)
    }
    
    /*
    15
    15
    */

    이러한 문제가 발생하는 이유는 area는 생성자로 객체가 초기화될 때 함께 초기화되는 필드이기 때문에 그 이후에 직사각형의 가로나 세로가 바뀌더라도 객체가 초기화될 당시에 넓이가 초기화된 상태로 저장되어 변하지 않기 때문이다. 이 문제를 해결하기 위해선 커스텀 getter를 사용할 수 있다.

     

    커스텀 getter를 작성하는 방법은 어렵지 않다. 변수를 작성할 때와 마찬가지로 val을 사용하여 변수를 선언하고 변수명 뒤에 get()을 선언하여 메소드를 작성하는 것과 비슷하게 작성한다. 반환값 타입은 메소드와 마찬가지로 등호(=)를 사용해 한줄로 작성하였을 때는 생략할 수 있지만, 코드 블럭을 생성하여 return을 사용할 경우에는 변수명 뒤에 타입을 명시해줘야 한다. 다음은 위의 Rectangle 클래스의 넓이를 커스텀 getter로 변경한 코드이다.

    class Rectangle(var width: Int, var height: Int) {
        val area get() = width * height
        /* 아래와 같이 작성해도 된다.
        val area: Int
            get() {
                return width * height
            }
        */
    }

    커스텀 getter를 사용하면 넓이를 호출할 때마다 현재 객체의 가로와 세로 길이를 토대로 계산하여 반환하게 된다.

    fun main() {
        val rectangle = Rectangle(3, 5)
        println(rectangle.area)
        rectangle.width = 4
        println(rectangle.area)
    }
    
    /*
    15
    20
    */

    커스텀 getter 역시 Java코드로 디컴파일해보면 별도의 getter로 변환되어 있는 것을 볼 수 있다.

    커스텀 getter는 Java 코드로 디컴파일하면 별도의 getter가 된다.


    커스텀 setter

    커스텀 setter는 기본적인 setter에 추가적인 기능을 부여하고자 할 때 사용한다. 커스텀 setter를 작성할 때 주의할 점은 커스텀 setter를 작성할 필드는 클래스의 기본 생성자에 필드를 작성하는 것이 아니라 클래스 내부에 필드를 작성하여 생성자의 파라미터를 받아와야 한다는 점이다. 필드 선언 아래에 set(value)를 선언하고 커스텀 getter와 마찬가지로 메소드를 작성하듯이 작성한다. 예를 들어 Person 클래스에서 이름을 변경할 때 반드시 대문자로 설정되는 setter를 작성한다. 

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

    예시의 Person 클래스는 생성자에서 name 필드가 선언된 것이 아니라 생성자는 단순히 파라미터로 name을 받아 필드의 name에 할당하는 것을 볼 수 있다. 그리고 바로 아래에 커스텀 setter가 작성되는데 field라는 것이 작성된 것을 볼 수 있다. 이 field에 마우스를 올려보면 바로 위에 선언되어 있는 필드라는 것을 알 수 있다.

    field는 커스텀 setter로 설정하는 필드를 의미한다.

    이제 Person 클래스는 객체를 새로 생성할 때는 name 필드에 그대로 들어가게 되지만 name 필드를 변경하게 되면 모두 대문자로 변경된다.

    fun main() {
        val person = Person("jack", 20)
        println(person.name)
        person.name = "chris"
        println(person.name)
    }
    
    /*
    jack
    CHRIS
    */

    커스텀 setter 역시 Java 코드로 디컴파일해보면 setter로 변환되는 것을 볼 수 있다.

    커스텀 setter는 Java 코드로 디컴파일하면 setter로 변환된다.


    마무리

    이번 포스트에서는 Kotlin 클래스의 커스텀 getter와 커스텀 setter에 대해 정리해보았다. 커스텀 getter는 객체에서 별도의 계산이 필요한 값을 얻어올 때 메소드 대신 사용할 수 있고, 커스텀 setter는 필드의 값을 변경할 때 추가적인 연산을 수행하게 해준다.

     

    다음 포스트에서는 Kotlin의 스코프 함수에 대해 정리할 예정이다.

     

    댓글 피드백은 언제나 환영합니다.

     

    댓글