Kotlin의 클래스 다루기
클래스와 프로퍼티
Java class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class JavaPerson {
private final String name;
private int age;
public JavaPerson(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
name은 final이기 때문에 setter
생성 불가 (불변의 특성)
- 프로퍼티 :
field
+getter
+setter
Kotlin class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person constructor(name: String, age: Int){
val name = name
var age = age
}
// 아래와 같이 constructor 생략 가능
class Person (name: String, age: Int){
val name = name
var age = age
}
// 아래와 같이 필드를 생성자에 직접 넣어서 사용할 수 있다.
// {} -> body 또한 존재하지 않는 다면 생략 가능
class Person (
val name: String,
var age: Int
)
Kotlin은 class를 생성할 때 생성자(constructor)를 같이 작성
- 프로퍼티 :
field
만 생성하면getter
+setter
를 자동으로 생성 - 생성자의 이름(constructor)는 생략할 수 있다.
field
를 생략하고 생성자에 넣기 가능{}
body 또한 존재 하지 않는 다면 생략 가능
Kotlin의 setter 사용법
1
2
3
4
5
6
7
8
9
10
11
val person = Person("김용준", 100)
println(person.name)
// 바로 값을 넣을 수 있다. (setter)
person.age = 10
println(person.age)
// Java class 를 가져 와서 쓴다고 해도 .field 를 사용할 수 있다.
val javaPerson = JavaPerson("김용준", 100)
println(javaPerson.name)
javaPerson.age = 10
println(javaPerson.age)
.field
를 사용해서 값을 바로 수정 가능
.field
를 사용해서 값을 바로 가져오기 가능
Java Class
를 가져와서 쓰는 경우에도 .field
를 사용 가능
생성장와 init
- 클래스가 생성되는 시점(초기화)에 한번 호출되는 블럭
1
2
3
4
class Person (
val name: String,
var age: Int
)
class
를 처음에 생성할 때 가지고 있는 생성자를 주 생성자(primary constructor)
라고 한다.
- 특징 : 반드시 존재해야 한다. 단, 주 생성자의 파라미터가 하나도 없다면 생략 가능
부 생성자
는 최종적으로주 생성자
를this
로 호출해야 한다.{}
body를 가질 수 있음
부 생성자는 사실상 쓸 일이 없다. 있다는 것을 알아만 두자!!
1
constructor(name: String): this(name, 1)
constructor
로 만든 생성자를 부 생상자(secondary constructor)
라고 한다.
- 특징 : 있을 수도, 없을 수도 있다.
나이는 0살 이상이어야 하는 예제
1
2
3
4
5
6
7
8
9
10
11
class Person (
val name: String,
var age: Int
){
// class(생성되는 시점) 가 초기화 되는 시점에 한번 호출되는 블럭
init {
if( age <= 0){
throw IllegalArgumentException("나이는 ${age}일 수 없습니다");
}
}
}
{}
body를 만들고 안에 init
블럭을 만들어서 초기화 시점에 호출
최초로 태어나는 아기는 무조선 1살인 생성자 예제
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Person (
val name: String,
var age: Int
){
// class(생성되는 시점) 가 초기화 되는 시점에 한번 호출되는 블럭
init {
if( age <= 0){
throw IllegalArgumentException("나이는 ${age}일 수 없습니다");
}
}
//새로운 생성자
constructor(name: String): this(name, 1)
}
constructor
를 사용해서 새로운 생성자를 만들 수 있음
부 생성자 호출 예제
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Person (
val name: String,
var age: Int
){
// class(생성되는 시점) 가 초기화 되는 시점에 한번 호출되는 블럭
init {
if( age <= 0){
throw IllegalArgumentException("나이는 ${age}일 수 없습니다");
}
println("초기화 블럭")
}
// 새로운 생성자
constructor(name: String): this(name, 1) {
println("첫 번째 부 생성자")
}
constructor(): this("홍길동") {
println("두 번째 부 생성자")
}
}
위에서 첫 번째 부 생성자
는 주 생성자
를 호출하고 두 번째 부 생성자
는 첫 번째 부 생성자
를 호출
- 1 .
첫 번째 부 생성자
는초기화 블럭
과첫 번째 부 생성자
을 출력 - 2 .
두 번째 부 생성자
는초기화 블럭
과첫 번째 부 생성자
과두 번째 부 생성자
를 출력
Kotlin은 사실 부 생성자 보다는 default parameter를 권장
1
2
3
4
class Person (
val name: String = "김용준",
var age: Int = 1
)
위와 같이 default parameter
를 사용 하도록 권장
어쩔 수 없이 써야 하는 경우?
Converting
과 같은 경우 부 생성자를 사용할 수 있지만, 정적 팩토리 메서드
를 추천
커스텀 getter, setter
성인인지 확인하는 기능 추가
Java의 경우
1
2
3
public boolean isAdult() {
return this.age >= 20;
}
Kotlin의 경우
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 전형적인 방식
fun isAdult(): Boolean {
return this.age >= 20
}
// custom getter
val isAdultV2: Boolean
get() = this.age >= 20
// (custom getter)프로퍼티
val isAdultV3: Boolean
get() {
return age >= 20
}
함수처럼 만드는 방식과 custom getter
로 만드는 방식 두가지 존재
효과적인 방법은?
객체의 속성 » custom getter
그렇지 않은 경우 » 함수
backing field (보이지 않는 필드)
1
2
3
4
5
6
7
8
9
10
11
class Person (
name: String = "김용준",
var age: Int = 1
){
// 원래 사용하던 val name: String = "김용준" 은 custom getter를 만들기 위해 아래로 내려서 get()으로 써준다
// field. 을 사용하는 이유 : 밖에서 호출할 때는 get()을 부르고 name이라는 필드가 먼저 호출
// 안에서도 name을 호출하면 name의 대한 getter가 호출된다.
// 안에 있는 getter를 부르고 부르는 무한 루프가 발생하게 된다.
val name = name
get() = field.uppercase()
- 원래 사용하던
val name: String = "김용준"
은custom getter
를 만들기 위해 아래로 내려서 get() 사용 field.
을 사용하는 이유- 밖에서 호출할 때는 get()을 호출하면 name이라는 필드가 먼저 호출
- 안에서도 name을 호출하면 name의 대한
getter
가 호출된다. - 안에서는 안에 있는
getter
를 부르고 부르는무한 루프
가 발생하게 된다.
field 예약어
- 무한 루프를 막기 위한 예약어로 자기 자신을 나타낸다
- 하지만
custom field
에서backing field
를 사용하는 경우는 드뭄
this로 대체 가능
backing field
를 사용하지 않는 예제
1
2
val upperCaseName: String
get() = this.name.uppercase()
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.