프로그래밍 언어/Kotlin

Kotlin의 class(1) - 생성 및 상속

Julie825 2022. 10. 3. 21:19

class란?

객체 지향 프로그래밍(OOP)에서 특정 객체를 생성하기 위해 변수와 메소드를 정의하는 일종의 틀(template)이다. 객체를 정의하기 위한 메소드와 변수로 구성된다. (출처 : 위키백과)

 

Kotlin에서 클래스를 만들 때는 class 키워드 뒤에 클래스 이름을 적고, {} 안에 원하는 내용을 적어주면 된다.

이때 body가 없는 경우에는 중괄호를 생략할 수 있다. ex) class Person{}

 

Constructor

해당 클래스의 인스턴스를 실제로 생성하는(초기화하는) 방식을 정의하는 특수한 메서드.

1. primary constructor

클래스 이름과 body 사이에 받을 값을 선언한다.

class MyClass(name: String, age: Int) {
    private val name = name
    var age = age
}

이때 대부분의 경우에는 받은 값을 그대로 클래스 속성에 넣어주게 될텐데, 이 경우에는 괄호 안에서 속성 선언까지 끝낼 수 있다. 아래 코드는 위 코드와 동일한 내용을 담고있다.

class MyClass( private val name: String, var age: Int )

굳이 constructor 키워드를 쓰겠다면 아래처럼 할 수도 있다.

내가 생각할 때 primary constructor를 가장 길게 쓸 수 있는 방법으로 보인다.

class MyClass {
    private val name: String
    var age: Int
    constructor(name: String, age: Int) {
    	this.name = name
        this.age = age
    }
}

 

변수에 값을 할당하는 것 외에 다른 동작( ex : for loop의 사용 등)이 없다면 init이 없어도 되지만, 한 줄로 끝나지 않는 작업일 경우에는 init 블럭 안에서 처리해줘야한다.

class Simple(
    val name: String,
    var age: Int = 0, // 인자가 여럿일 때 trailing comma로 추가 및 변경 쉽게할 수 있음
) {
    val customerKey = name.uppercase() // 메서드 호출 정도는 init 불필요
}

class Complicate(
    val name: String,
    var age: Int,
) {
    val introduction: String // init 블럭에서 정의된다면 late init이 아니다.

    init {
        val schoolType = if (age > 19) {"대학생"} else {"고등학생"}
        introduction = "안녕하세요 저는 $name 이고, $age$schoolType 입니다."
    }
}

 

예시에서는 init 블럭이 하나지만, init은 클래스 하나에 여러개 쓸 수 있다. 이때 각 블럭은 위에서부터 순서대로 실행된다.

 

Tip ) 외부에서 객체를 생성하지 못하게 하는 방법 - private constructor

위에서 본 예시에서는 contructor를 생략할 수 있었지만, 이렇게 private으로 지정해줄 때는 반드시 붙여줘야한다. 

class Single private constructor() {}

 

2. secondary constructor

primary constructor에서 받는 인자 외의 다른 형태로도 객체를 초기화하고 싶을 수 있다.

이럴 때 constructor 키워드를 이용해서 secondary constructor를 만들어주면 된다.

secondary constructor는 : this()로 primary constructor를 호출해서 원하는 값을 넣어주는 방식으로 동작한다.

class MyClass(val num: Int) {

    // secondary constructor
    constructor(num1: Int, num2: Int) : this(num1 + num2)
}

 

속성

property는 val(수정 불가)이 될 수도, var(수정가능)이 될 수도 있다.

따로 private 키워드를 붙여주지 않으면 클래스 외부에서도 접근할 수 있는 public 속성이 된다.

class MyClass {
    val A = "Immutable | Public" // 클래스 외부 print 가능 재할당 불가
    var B = "Mutable | Public"   // 클래스 외부 print 가능 재할당 가능
    private val C = "Immutable | Private" // 클래스 외부작업 아예 불가
    private var D = "Mutable | Private"   // 클래스 외부작업 아예 불가
}

속성 타입으로 람다함수나 inner class를 넣으면 더 다양한 작업을 할 수 있다.

 

getter와 setter에서 타입은 inffered될 수 있지만 선언하려면 아래와 같이 수행한다.

class Rectangle(val width: Int, val height: Int) {
    val area: Int // property type is optional since it can be inferred from the getter's return type
        get() = this.width * this.height // custom accessors

		// 한 줄로 쓸 수도 있다.
		val height get() = this.height.toString() 
		
		var editMe : Int
			get() = this.editMe.toString
			set(value){...} // value라고 쓰는게 컨벤션이다.
}

 

Tip ) 속성을 밖에서 수정할 수 없게 만드는 방법 - private set

속성을 밖에서 변경할 수 없게 만들 때 val을 쓰면 된다고 생각할 수도 있지만 그러면 내부에서도 수정이 안되는 문제가 생긴다. 이 문제는 단순히 변수 선언부 아래에 탭을 들여넣고 setter를 private으로 설정하는 것으로 해결된다.

class Persen(){
	var hobby : String = "singing"
		private set
}

 

 

 

Instance 생성

인스턴스화는 실제로 메모리에 객체를 위한 자리를 할당하는 과정이다. 주로 아까 만들어둔 Constructor를 사용한다.

  • val 변수명 = 클래스()

참고한 자료

Kotlin 공식 사이트 - class : https://kotlinlang.org/docs/classes.html