본문 바로가기
Android

[Doit 깡샘의 안드로이드 앱 프로그래밍 with 코틀린] 정리 4 - 클래스와 생성자

by 들풀민들레 2022. 2. 28.
본 글은 [Doit 깡샘의 안드로이드 앱 프로그래밍 with 코틀린 - 이지스퍼블리싱 (2022)] 의 내용을 발췌한 것입니다.
좀더 자세한 내용은 책 혹은 인강을 통해 확인해 주세요.

 

 

 

 

클래스 선언


코틀린에서 클래스는 class 키워드로 선언합니다. 다음 코드에서 class User 부분이 클래스의 선언부이며 중괄호 { } 영역이 본문입니다. 만약 클래스의 본문에 입력하는 내용이 없다면 { }를 생략할 수 있습니다.

 

 

class User { }

 

클래스의 멤버는 생성자, 변수, 함수, 클래스로 구성됩니다. 이 중에서 코틀린의 생성자는 constructor라는 키워드로 선언하는 함수입니다. 그리고 클래스 안에 다른 클래스를 선언할 수도 있습니다.

 

class User {
	var name = “kkang”
	constructor(name: String) {
		this.name = name
	}
	fun someFun() {
		println(“name : $name”)
	}
	class SomeClass { }
}

 

클래스는 객체를 생성해 사용하며 객체로 클래스의 멤버에 접근합니다. 그런데 코틀린에서는 객체를 생성할 때 new 키워드를 사용하지 않습니다. 오른쪽 코드에서 User("kim")이 객체를 생성하는 구문이며 클래스 이름과 같은 함수로 객체를 생성합니다.
객체를 생성할 때 생성자가 자동으로 호출되므로 소괄호 안에 전달한 인자는 클래스에 선언된 생성자의 매개변수와 들어맞아야 합니다. 앞에서 작성한 User 클래스의 생성자는 constructor (name: String)이므로 문자열 데이터를 전달받는 매개변수가 있습니다. 따라서 객체를 생성할 때 User(“kim”)처럼 문자열 데이터를 전달해 주어야 합니다.

 

val user = User(“kim”)
user.someFun()

 

주 생성자


코틀린 클래스는 생성자를 주 생성자와 보조 생성자로 구분합니다. 한 클래스 안에 주 생성자만 선언할 수도 있고 보조 생성자만 선언할 수도 있습니다. 물론 둘 다 선언할 수도 있습니다.
주 생성자는 constructor 키워드로 클래스 선언부에 선언합니다. 주 생성자 선언은 필수는 아니며 한 클래스에 하나만 가능합니다.

class User constructor() {
}

주 생성자를 선언할 때 constructor 키워드는 생략할 수 있습니다.

class User() {
}

만약 개발자가 클래스의 주 생성자를 선언하지 않으면 컴파일러가 매개변수가 없는 주 생성자를 자동으로 추가합니다.

class User {
}

 

주 생성자의 매개변수


주 생성자를 선언할 때 필요에 따라 매개변수를 선언할 수도 있습니다.

 

class User(name: String, count: Int) {
}

앞의 코드는 User 클래스를 선언하면서 주 생성자에 매개변수를 2개 선언했습니다. 그러면 객체를 생성할 때 매개변수의 타입과 개수에 맞는 인자를 전달해야 합니다.

 

val user = User(“kkang”, 10)

 

주 생성자의 본문 ― init 영역


주 생성자를 이용해 객체를 생성할 때 특정한 로직을 수행할 수 있습니다. 그런데 주 생성자의 실행 영역인 본문을 다음처럼 추가하면 오류가 발생합니다.

 

class User(name: String, count: Int) {
// 주 생성자 본문
} { // 오류!
// 클래스 본문
}

보통 클래스나 함수의 본문(실행 영역)은 중괄호 { }로 감싸지만 주 생성자에는 { }를 추가할 수 없습니다. 왜냐하면 주 생성자는 클래스 선언부에 있기 때문입니다. 이럴 때 init 키워드를 이용해 주 생성자의 본문을 구현할 수 있습니다.


코틀린의 클래스 안에서 init 키워드로 지정한 영역은 객체를 생성할 때 자동으로 실행됩니다. 클래스에서 init 영역은 꼭 선언할 필요는 없으므로 주 생성자의 본문을 구현하고 싶을 때 사용합니다.


init 영역은 주 생성자뿐만 아니라 잠시 후에 다루는 보조 생성자로 객체를 생성할 때도 실행됩니다. 하지만 보조 생성자는 클래스 안에 선언하므로 { }를 이용해 본문을 지정할 수 있습니다. 따라서 init 영역은 일반적으로 주 생성자의 본문을 구현하는 용도로 사용합니다.

 

class User(name: String, count: Int) {
	init {
		println(“i am init....”)
	}
}

fun main() {
	val user = User(“kkang”, 10)
}

User라는 클래스에 주 생성자를 선언하고 클래스 본문에 init 영역을 두어 주 생성자의 본문을 작성했습니다. 이렇게 하면 main() 함수에서 User 클래스의 객체를 생성할 때 init 영역에 작성한 코드가 자동으로 실행됩니다.


생성자의 매개변수를 클래스의 멤버 변수로 선언하는 방법


생성자의 매개변수는 기본적으로 생성자에서만 사용할 수 있는 지역 변수입니다.

 

class User(name: String, count: Int) {
	init {
		println(“name : $name, count : $count”) // 성공!
	}
	fun someFun() {
		println(“name : $name, count : $count”) // 오류!
	}
}

위 코드에서는 주 생성자에 name, count 매개변수를 선언했습니다. 그리고 이 변수를 init 영역과 someFun()이라는 함수에서 사용하려고 합니다. 생성자를 호출할 때 init 영역이 실행되므로 이곳에서 생성자의 매개변수에 접근할 수 있습니다.
하지만 생성자의 매개변수는 지역 변수이므로 다른 함수에서는 사용할 수 없습니다. 만약 생성자의 매개변수를 클래스의 멤버 변수처럼 다른 함수에서 사용해야 한다면 다음처럼 작성해야 합니다.

 

class User(name: String, count: Int) {
	// 클래스 멤버 변수 선언
	var name: String
	var count: Int
	init {
		// 클래스 멤버 변수에 생성자 매개변숫값 대입
		this.name = name
		this.count = count
	}
	fun someFun() {
		println(“name : $name, count : $count”) // 성공!
	}
}

fun main() {
	val user = User(“kkang”, 10)
	user.someFun()
}

클래스의 멤버 함수 someFun()에서 생성자의 매개변수를 이용하고자 클래스의 멤버 변수를 선언하고 주 생성자의 본문인 init 영역에서 매개변숫값을 클래스의 멤버 변수에 대입했습니다.
그런데 이런 방법 말고 생성자의 매개변수를 클래스의 멤버 변수로 선언하는 방법이 있습니다. 이렇게 하면 코드를 조금 더 간단하게 작성할 수 있습니다. 주 생성자의 매개변수는 생성자 안에서만 사용할 수 있는 지역 변수지만 매개변수를 var나 val 키워드로 선언하면 클래스의 멤버 변수가 됩니다.

 

class User(val name: String, val count: Int) {
	fun someFun() {
		println(“name : $name, count : $count”) // 성공!
	}
}

fun main() {
	val user = User(“kkang”, 10)
	user.someFun()
}

원래 함수는 매개변수를 선언할 때 var나 val 키워드를 추가할 수 없습니다. 그런데 주 생성자에서만 유일하게 var나 val 키워드로 매개변수를 선언할 수 있으며 이렇게 하면 클래스의 멤버 변수가 됩니다. 따라서 위 코드에서 생성자의 매개변수 name과 count를 someFun()이라는 멤버 함수에서 사용할 수 있습니다.