본문 바로가기
깡샘 코틀린

04-1 클래스와 생성자

by 농농씨 2023. 6. 13.

class User {}

class User: 클래스의 선언부

{}: 본문 영역(내용 없으면 생략 가능)

 

클래스의 멤버

: 생성자,변수,함수,클래스

코틀린의 생성자: constructor라는 키워드로 선언하는 '함수'

더보기

생성자란?

생성자(Constructor)는 객체가 생성될때 '자동으로' 호출되는 특수 목적의 멤버함수(메소드)로 객체의 초기화를 위해 사용됩니다.

생성자는 클래스에 최소 1개는 있어야 하며, 생성자 코드가 없을 경우 컴파일러가 기본생성자를 자동으로 생성합니다. 

 

참조:https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwiIl_GKh7j_AhUFHXAKHfR3AJUQFnoECBkQAQ&url=https%3A%2F%2Fkadosholy.tistory.com%2F91&usg=AOvVaw11OnEt-i8gfvdx-Wi6Tbzb

클래스 안에 다른 클래스 선언하기도 가능

클래스는 객체를 생성해 사용하며 객체로 클래스의 멤버에 접근함.

//클래스의 멤버: 생성자, 변수, 함수, 클래스
class User {
	var name = "kkang"
    constructor(name: String) { // constructor 키워드로 생성자 함수 선언
    	this.name = name
        /*
        	자바에서의 this 키워드는 해당 키워드를 사용한 클래스 자신을 지칭할 때 사용하며, 
        	코틀린에서도 동일한 용도로 사용된다.
        */
    }
    fun someFun() { // 함수 선언하고 name 속성 출력하도록 함
    	println("name : $name")
    }
    class SomeClass {} // 클래스 안에 다른 클래스 선언함
}

//객체 생성과 멤버 접근
val user = User("kim") 
/*
	코틀린에서는 new 키워드를 사용하지 않고 객체를 생성함
    또한 내부에서는 constructor라는 키워드를 쓰지만 외부에서는 클래스와 동일한 이름의 함수로 객체를 생성함
    객체를 생성할 때 생성자가 '자동으로' 호출되므로,
    소괄호 안에 전달한 인자는 클래스에 선언된 생성자의 매개변수와 들어맞아야 한다.
*/
user.someFun()

여태까지 썼던건
class User: Int(val:"name",val:"age"){
	//이런건데~
}

 

주 생성자와 보조 생성자

코틀린의 생성자는 주 생성자와 보조 생성자로 나뉨

한 클래스 안에 주 생성자만 생성할 수도, 보조 생성자만 생성할 수도 있음

 

주 생성자

constructor 키워드로 클래스 선언부에 선언. constructor 생략가능

한 클래스에 하나만 선언가능

선언하지 않으면 컴파일러가 매개변수 없는 주 생성자를 '자동으로' 추가함

필요에 따라 매개변수를 선언할 수도 있음

class User constructor() // 주 생성자 선언
class User() { //constructor 키워드 생략 예
}
class User { // 매개변수가 없는 주 생성자 자동 선언
}
class User(name: String, count: Int) { // 매개변수도 선언한 주 생성자
}

 

주 생성자의 본문-init영역(??이해가 안가요)

주 생성자의 본문을 다음처럼 추가하면 오류가 발생함

// 주 생성자 중괄호 때문에 오류 발생
class User(name: String, count: Int) { // 클래스 이름 바로 옆에 넣는 게 생성자!?
	// 주 생성자 본문
}{  // 오류!
	// 클래스 본문
}

 

보통 클래스나 함수의 본문(실행 영역)은 중괄호{}로 감싸지만, 주 생성자에는 {}를 추가할 수 없다.

왜냐하면!

주 생성자는 클래스 선언부에 있기 때문이다. (선언부에 있으면 {}를 추가할수없는건가보다)이럴때! 'init'키워드를 쓰면 된다~(?)

/*

코틀린의 클래스 안에서 init키워드로 지정한 영역은 객체를 생성할 때 자동으로 실행됩니다.(initialize)

클래스에서 init영역은 꼭 선언할 필요는 없으므로 주 생성자의 본문을 구현하고 싶을 때 사용함.

init 영역은 주 생성자 뿐만 아니라 뒤에 나오는 보조 생성자로 객체를 생성할 때도 실행됨.

하지만 보조 생성자는 클래스 안에 선언하므로 {}를 이용해 본문을 지정할 수도 있다.

따라서 init 영역은 일반적으로 주 생성자의 본문을 구현하는 용도로 사용한다.

*/

 

//init 키워드로 주 생성자의 본문 지정
class User(name: String, count: Int) {
	init { // init 키워드로 지정한 영역은 객체 생성시 자동 실행됨
    	println("I am init...")
    }
}
fun main() { // 함수를 선언함
	val user = User("kang", 10) // User클래스의 객체를 생성하고 문자열과 숫자를 인자로 전달하는.
}

 

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

'생성자'의 '매개변수'는 기본적으로 생성자에서만 사용할 수 있는 '지역 변수'이다.(생성자 본문 밖에서는 못쓴다는 뜻. 클래스 내부여도!)

따라서 다른 함수에서 사용할 수 없지만, 클래스의 '멤버변수'처럼 다른 함수에서 사용해야 한다면 다음과 같이 하면 된다.

// 생성자의 매개변수
class User(name: String, count: Int) {
	init {
    	println("name : $name, count : $count") // init 내부에서 생성자의 매개변수 사용
    }
    fun someFun(){
    	println("name : $name, count : $count") // init 외부에서 생성자 매개변수를 그냥 사용하면 오류남
    }
}

// 생성자 매개변수를 클래스의 멤버변수처럼 클래스 내부의 다른 함수에서도 자유롭게 사용하고 싶다면?
class User(name: String, count: Int) {
	// 클래스 멤버 변수 선언
    var name: String
    var count: Int // 이런 식으로 클래스 내부에서 멤버변수를 선언해주고
    init{
    	// 그 클래스 멤버 변수에 생성자 매개변숫값을 대입함 
    	this.name = name // this.name의 name은 멤버변수, 그냥 name은 생성자꺼
        					// 기본적으로 init에서는 생성자 본문이니까
        this.count = count
    } // 그러면 init은 선언부는 클래스 안에 있지만 클래스를 별도로 호출해야하는 거 보면 클래스에 속해있지는 않은 거라고 봐야하나
    fun someFun() {
    	println("name : $name, count : $count") // 멤버변숫값이 잘 대입된 멤버변수들~ 출력가능해짐~
    }
}
fun main() {
	val user = User("kkang, 10") //클래스의 객체 생성
    user.someFun() // 함수를 밖에서 호출할 수도 있다~
}

더 간단하게 하고 싶다면!

주 생성자의 매개변수는 생성자 안에서만 사용할 수 있는 지역 변수지만,

매개변수를 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 키워드를 추가할 수 없다. but 주 생성자에서만 유일하게 var나 val 키워드로 매개변수를 선언할 수 있으며, 이렇게 하면 클래스의 멤버변수가 된다. 따라서 클래스에 선언한 함수에서 생성자의 매개변수를 사용할 수 있게 된다.

Q. 클래스의 멤버변수로 선언하지 않은 생성자의 매개변수를, 메인함수에서 호출할 수 있는지 궁금하다.

 

 

보조 생성자

클래스의 본문 안에 constructor 키워드로 선언하는 함수로서, 클래스 본문에 선언하므로 여러 개를 추가할 수 있음

(본문인 중괄호{}밖에 쓰면 주 생성자고 본문 안에 쓰면 보조 생성자다~)

보조 생성자도 생성자이므로 객체를 생성할 때 자동으로 호출됨.(아마 형식에 맞는거만 호출되나?)

또한, 보조 생성자는 클래스 본문에 선언하므로 본문을 중괄호{}로 묶어서 객체 생성과 동시에 실행할 영역을 지정할 수 있다.

(<->주 생성자는 중괄호 직접 못쓰고 init{}으로 본문 구현함)

// 보조 생성자 선언 예시
class User {
	// 매개변수를 다르게 선언한 보조 생성자 두개 예시
	constructor(name: String) {
    	println("constructor(name: String) call...")
    } // 보조 생성자의 본문도 주 생성자의 본문처럼 객체 생성과 동시에 실행됨(실행 결과 참조)
    constructor(name: String, count: Int) { // 두번째 보조생성자여도 constructor 키워드 그대로 씀
    	println("constructor(name: String, count: Int) call...")
    }
}
fun main() {
	val user1 = User("kkang") // 첫번째 보조생성자 호출
    val user2 = User("kkang", 10) // 두번째 보조생성자 호출
}

실행결과:
constructor(name: String) call...
constructor(name: String, count: Int) call...

 

보조 생성자에 주 생성자 연결

클래스를 선언할 때 두 생성자 중 하나만 선언하면 문제가 없지만, 만약 주 생성자와 보조 생성자를 모두 생성한다면 반드시 생성자끼리 연결해주어야 함.

// 주 생성자와 보조 생성자의 선언 시 오류
class User(name: String) {
	constructor(name: String, count: Int) { // 오류!
    	// 생략
    }
}

주 생성자가 없다면 보조 생성자를 선언하는 데 문제가 없지만, 주 생성자가 있으므로 보조 생성자에서 주 생성자를 호출해주어야 함!!!

보조 생성자는 객체를 생성할 때 호출되며, 이때 클래스 내에 주 생성자가 있다면 this() 구문을 이용해 주 생성자를 호출해야 함

// 보조 생성자에서 주 생성자 호출
class User(name: String) {
	constructor(name: String, count: Int): this(name) {
    // 보조 생성자가 주 생성자를 '상속'받는 개념...?
    // this는 클래스 자신을 가리킨다는 점...
    	// 생략
    }
}
fun main() {
	val user = User("kkang", 10)
    //보조 생성자로 객체를 생성할 때 주 생성자가 함께 호출됨
}

(보조생성자 개념 복습-https://dreaminsweetpotato.tistory.com/10

주 생성자로 객체가 생성될 수도 있고, 보조 생성자로 객체가 생성될 수도 있다. 

예를들어 나이를 기본값을 설정해놓고, 기본값과 나이가 같은 객체는 주 생성자로 이름만 입력해주고, 나이가 기본값과 다른 객체는 보조생성자로 나이를 따로 기입해서 객체 생성!)

+만약 주 생성자가 있는 상태에서 보조 생성자를 여러 개 선언한다면 보조 생성자에서 this()로 다른 보조 생성자를 호출할 수도 있다(!!보조 생성자끼리도 상속받을 수 있나보군) 그러나 이때에도 보조 생성자로 객체를 생성한다면 어떤 식으로든 주 생성자가 호출되게 해야한다!

(한마디로 주 생성자는 어떤 경우에든 필수로 호출되어야 한다~)

// 보조 생성자가 여럿일 때 생성자 연결
class User(name: String) {
	constructor(name: String, count: Int): this(name) {
    	// 생략
    }
    constructor(name: String, count: Int, email: String): this(name, count) {
    	// 생략
    }// 두번째 보조생성자는 첫번째 보조생성자를 상속받았지만(호출하지만)
    // 첫번째 보조생성자가 주 생성자를 호출하므로
    // 세번째 보조생성자를 이용하여 객체를 생성할 때도 결국 주 생성자가 호출됨!>_0
}
fun main() {
	val user = User("kkang", 10, "a@a.com")
}

(흠... 기본값을 설정하고 보조생성자로 기본값을 변경하는 예시만 봐서..

Q1.주 생성자로 이름만 입력해도 괜찮은걸까➡️해봐야함

constructor(name:String) : this(name, 1997) 이런식으로 주 생성자에 값을 입력한 채로 보조 생성자에 상속해줄수도 있군!

Q2.주생성자의 매개변수랑 보조 생성자의 매개변수 개수는 뭐가 더 많든 상관 없는건가➡️주생성자보다 모자라면 안됨! 보조생성자 매개변수가 주생성자보다 매개변수가 적다면, 상속해줄때 기본값을 지정해줘야 하는듯.

)

'깡샘 코틀린' 카테고리의 다른 글

05-1 람다 함수와 고차 함수  (0) 2023.06.15
04-3 코틀린의 클래스 종류  (0) 2023.06.14
04-2 클래스를 재사용하는 상속  (0) 2023.06.14
03 코틀린 시작하기  (0) 2023.06.06
02 안드로이드 앱의 기본 구조  (0) 2023.06.04