[Kotlin] 클래스

백현균·2023년 4월 16일

1. 클래스와 프로퍼티

1) 코틀린에서는 getter,setter를 자동으로 생성

// 멤버변수만 생성해도, 알아서 getter,setter 사용 가능
public class Person(name:String, age:Int){
	val name:String = name
    var age:Int = age
}

2) 생성자에서 프로퍼티 생성 가능

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

3) 클래스명.변수로 호출 가능

* 자바로 만들어진 클래스도 변수명으로 호출

* get, set함수가 아닌 변수명으로 직접 호출
fun main(){
	val person = Pseron("test", 50)
    println(person.name)
    println(person.age)
    
    pserson.age = 27
}

2. 생성자와 init

1) 코틀린에서는 init함수를 통해 초기 조건이나, 값 할당 가능

public class Person(val name:String, var age:Int){
	init{
    	if(age <= 0){
        	throw IllegalArgumentException("맞지 않는 나이")
        }
    }
}

2) constructor키워드를 통해 추가 생성자를 만들 수 있음

public class Person(val name:String, var age:Int){
	init{
    	if(age <= 0){
        	throw IllegalArgumentException("맞지 않는 나이")
        }
    }
    
    // 새로운 생성자 생성
    // this는 결국 맨 위의 생성자를 가리킴
    constructor(name:String):this(name, 1)
}

* 주생성자(primary constructor)

- public class Person(val name:String, var age:Int){...} 
  와 같은 최초에 생성되는 생성자를 의미
- 반드시 존재해야하며, 파라미터가 하나도 없을 경우 생략 가능

* 부생성자(secondary constructor)

- constructor(name:String):this(name, 1) 와 같이 부가적인 생성자를 의미
- 추가적으로 생성자를 만들고 때 생성되는 생성자이므로 없어도 무방함
- 최종적으로 주생성자를 this 형태로 호출해야함.
- 부생성자는 body를 가질 수 있다

* 예시

public class Person(val name:String, var age:Int){
	// 부생성자가 여러개 있어도 최종적으로 주생성자를 호출
    constructor(name:String):this(name, 1){
   		println("첫 번째 부생성자")
    }
    constructor():this("test"){
    	println("두 번째 부생성자")
    }
}

* 코틀린에서는 부생성자보단 디폴트 파라미터를 권장함

* Converting과 같은 경우 부생성자를 사용할 수 있으나, 정적 팩토리 메소드를 추천

3. 커스텀 getter, setter

1) 커스텀을 통해, 프로퍼티가 있는 것처럼 처리할 수 있음

public class Person(val name:String, var age:Int){
	init{
    	if(age <= 0){
        	throw IllegalArgumentException("맞지 않는 나이")
        }
    }
    
    constructor(name:String):this(name, 1)
    
    // 위 아래는 같은 표현
    val isAduld:Boolean
    	get() = this.age >= 20
        
	val isAduld:Boolean
		get() {
			return this.age >= 20
		}
}

2) 커스텀 getter 실전 예제

* Name을 첫 글자를 무조건 대문자로 만들때

public class Person(name:String, var age:Int){

	val name = name
    	get() = field.uppercase()

	init{
    	if(age <= 0){
        	throw IllegalArgumentException("맞지 않는 나이")
        }
    }
    
    constructor(name:String):this(name, 1)
    
    // 위 아래는 같은 표현
    val isAduld:Boolean
    	get() = this.age >= 20
        
	val isAduld:Boolean
		get() {
			return this.age >= 20
		}
}

4. backing field

1) field키워드

호출되는 곳에서 name을 호출하게되면, 내부에서 get을 호출
get내부는 또 멤버변수 name을 호출하게되고, 다시 또 get을 호출 
-> 즉 무한루프 발생

이런 현상을 막기위해 자기 자신(멤버의 name)을 가리키는 
field키워드를 사용

2) 예시

* backing field키워드를 사용하지 않고도 구현 가능

public class Person(name:String, var age:Int){
	var name = name
    	get() = field.uppercase()
        // value는 대입되는 값, field는 자기자신
        set(value){
        	field = value.uppercase()
        }  
        
    val uppercaseName = 
    	get() = this.name.uppercase()

    fun getUppercaseName() = this.name.uppercase()

	init{
    	if(age <= 0){
        	throw IllegalArgumentException("맞지 않는 나이")
        }
    }
    
    constructor(name:String):this(name, 1)
    
    // 위 아래는 같은 표현
    val isAduld:Boolean
    	get() = this.age >= 20
        
	val isAduld:Boolean
		get() {
			return this.age >= 20
		}
}

* setter를 지양하고있고, update함수를 통해 값 변경을 주로 진행하기 때문에, custom setter는 잘 사용하지 않음

0개의 댓글