728x90
클래스와 프로퍼티
class KotlinPerson constructor(name: String, age: Int){
val name = name
val age = age
}
- 코틀린에서는 필드만 만들면 getter와 setter를 자동으로 만들어준다.
- property = field + getter + setter
- constructor는 생략할 수 있다.
class KotlinPerson(
name: String,
age: Int
){
val name = name
val age = age
}
- 클래스의 필드 선언과 생성자를 동시에 선언할 수 있다.
- 생성자: constructor(name: String, age: Int)
- 필드
- val name = name
- val age = age
- .필드 를 통해서 getter와 setter를 바로 호출한다.
- 자바 클래스, 코틀린 클래스 상관없음.
// kotlin class 이용
val kotlinPerson = KotlinPerson("kotlinUser", 100)
// getter
println(kotlinPerson.name)
// setter
kotlinPerson.age = 10
println("kotlinPerson.age = ${kotlinPerson.age}")
// java class 이용
val javaPerson = JavaPerson("javaUser", 30)
// getter
println(javaPerson.name)
// setter
javaPerson.age = 50
println("javaPerson.age = ${javaPerson.age}")
생성자와 init
- 클래스가 생성되는 시점에 나이 검증
- 자바: 생성자에 검증 부분을 넣어준다.
- 코틀린: init(초기화) 블록을 이용하면 생성자가 호출되는 시점에 호출된다.
- init: 값을 적절히 만들어주거나, validatio하는 로직
init {
if (age <= 0) {
throw IllegalArgumentException("나이(${age})는 1 이상이어야 합니다.")
}
}
- 최초로 태어나는 아기는 무조건 1살이다. -> 생성자를 하나 더 만든다.
- 자바: this를 사용해서 나이가 무조건 1살인 생성자를 하나 더 만든다.
- 코틀린: constructor(parameter)로 생성자를 추가하고, : this(name, 1)로 주생성자(primary constructor)를 호출한다.
- 주생성자(primary constructor)
- 반드시 존재해야 한다.
- 단, 주생성자에 파라미터가 하나도 없다면 생략이 가능하다.
- 부생성자(secondary constructor)
- 있을수도 있고, 없을수도 있다.
- 최종적으로 주생성자를 this로 호출해야 한다.
- body를 가질 수 있다.
- 주생성자(primary constructor)
// 부생성자 사용
class KotlinPerson1(
// 주생성자
name: String,
age: Int
){
val name = name
var age = age
init {
if (age <= 0) {
throw IllegalArgumentException("나이(${age})는 1 이상이어야 합니다.")
}
println("초기화 블록")
}
// 부생성자 - 최초로 태어나는 아기는 무조건 1살이다.
constructor(name: String): this(name, 1){
println("부생성자1")
}
constructor() : this("user"){
println("부생성자2")
}
override fun toString() = "KotlinPerson(name=${name}, age=${age})"
}
- BUT, 부생성자보다는 default parameter를 권장한다.
- Converting과 같은 경우는 부생성자를 사용할 수 있지만, 그보다는 정적 팩토리 메서드를 추천한다.
// default parameter 사용
class KotlinPerson2(
val name: String = "user",
var age: Int = 100
) {
init {
if (age <= 0) {
throw IllegalArgumentException("나이(${age})는 1 이상이어야 합니다.")
}
}
override fun toString() = "KotlinPerson(name=${name}, age=${age})"
}
커스텀 getter, setter
- 모두 동일한 기능이고, 표현 방법만 다르다.
fun isAdult(): Boolean{
return this.age >= 20
}
- 객체의 속성과 관련된 기능이라면, custom getter를 사용한다.
val isAdult: Boolean
get() = this.age >= 20
val isAdult: Boolean
get() {
return this.age >= 20
}
- custom getter를 사용하면, 자기 자신을 변형해 줄 수 있다.
// name 을 get 할 때, 무조건 대문자로 바꾸기
val name: String = name
get() = field.uppercase()
- 주생성자에서 받은 name을 불변 프로퍼티 name에 바로 대입시켜 준다.
- name에 대한 custom getter를 만들 때, field를 사용한다.
- get() = name.uppercase() 이면,
- name은 name에 대한 getter를 호출하니까 다시 get을 부른다.
- getter 안에는 다시 name이 있으므로, 무한루프가 발생한다.
backing field
- 무한루프를 막기 위한 예약어로 자기 자신을 가리킨다.
- 실무에서는 custom getter에서 backing field를 사용하는 경우는 드물다.
- 밖에서 볼 때, 우리가 원하는 요구사항을 달성하는 프로퍼티가 하나 더 있는 것처럼 보여줄 수 있기 때문
val upperCaseName: String
get() = this.name.uppercase()
- name을 set할 때, 무조건 대문자로 바꿔주기
// name 을 set 할 때, 무조건 대문자로 바꿔주기
var name: String = name
set(value) {
field = value.uppercase()
}
728x90