티스토리 뷰
Author: 니용
데이터 클래스(Data Class)는 Java에서 DTO의 역할을 하는 클래스와 같습니다. Bean이죠.
특징이 있다면 생성자가 자동으로 생성되는 구조로 되어 있습니다. 예시로 바로 넘어가 보겠습니다.
Java의 경우 이러한 형식으로 DTO를 생성하곤 했습니다.
public class Abbo {
private Integer id;
private String nickname;
// constructor
public Abbo(@NotNull Integer id) {
this.id = id;
}
// getter
public getId() {
return this.id;
}
// setter
public setId(Integer id) {
this.id = id;
}
// toString()
@Override
public String toString() {
// ...
}
// hashCode()
@Override
public int hashCode() {
// ...
}
// equals()
@Override
public boolean equals(Abbo another) {
// ...
}
// copy()
@Override
public final Abbo copy(@NotNull Integer id) {
return new Abbo(id);
}
}
이러한 소스가 Kotlin에서 간편해집니다.
data class Abbo(val id: Int) {
private val nickname : String
}
여기서 주의해야 할 점은 적어도 1개 이상의 파라미터를 입력받아야 합니다.
특이한 점은 이렇게 파라미터로 받은 것이 Default 생성자의 재료가 됩니다.
data class내에 생성자를 직접 만들 수도 있습니다. 하지만 개발 퍼포먼스가 빠른 Kotlin의 장점이 의미가 없어집니다.
data class Abbo(val id: Int) {
constructor() {
// logic ...
}
}
파라미터는 val과 var 둘 다 사용 가능합니다.
그리고 abstract(추상), open(상속), sealed(인터페이스), inner(내부 클래스)의 특성을 붙일 수 없습니다.
오버라이드(Override)하게 되는 경우, 직접 구현된 코드를 사용할 수 있습니다. 선언 방식은 Java와 조금씩 차이가 있습니다.
data class Abbo(val id: Int) {
val nickname: String
override fun toString(): String {
return "id: ${id}, nickname: ${nickname}"
}
}
데이터 클래스의 사용
(Kotlin으로 넘어오면서 new 키워드가 사라졌습니다!!)
네 맞습니다. new를 사용하지 않게 되었습니다.
기본적으로 위에서 선언된 멤버 변수는 다른 클래스에서 이렇게 사용합니다.
fun useModel() {
var id: Int = 1
var abbo : Abbo(id)
print(abbo)
}
Destructing Declarations
Kotlin의 data class에는 특이한 성질이 있습니다. 바로 같은 data class이지만 파라미터의 순서를 변경해서 호출할 수 있습니다. 가령 복잡한 data class가 있다고 예제를 들어보겠습니다.
data class Abbo(val id: Int
, val nickname: String
, val name: String?
, val age: Int
, val loginCount: Int
, val lastLoginDatetime: LocalDateTime?) {
var password: String = ""
var auth: String = ""
var authLevel: Int = 0
}
// 기존 자바에서 썼던 방법
var obj: Abbo = Abbo(1, "Niyo", null, 99, 3, LocalDateTime.now())
위의 경우에서 생성자가 생성될 때는 모두 파라미터의 순서 규칙에 따라 정의해주었어야 하였습니다.
하지만 파라미터로 받아야 하는 것이 무한정 늘어나는데, 정작 필요 없는 파라미터가 있거나 순서를 정하기 어려울 정도로 많아지면 어떻게 하는 것이 좋을까요?
이러한 불편함을 줄이기 위해 개선되었습니다.
data class Abbo(val id: Int
, val nickname: String
, val name: String?
, val age: Int
, val loginCount: Int
, val lastLoginDatetime: LocalDateTime?) {
var password: String = ""
var auth: String = ""
var authLevel: Int = 0
}
// 키값에 맞춰 설정
var obj: Abbo(
nickname = "Niyo"
, age = 99
, lastLoginDatetime = LocalDateTime.now()
, id = 1
, name = null
, loginCount = 3
)
파라미터가 순서 상관없이 정의되었습니다! 다만 여기서 불필요한 파라미터인 null이 들어가고 있지만 이 값이 필수 값인지라 빼기는 어렵네요. 이러한 성질을 데이터 분해와 대입(Destructing Declarations)라고 합니다.
Getter / Setter
그럼 생성된 객체의 값을 가져오는 것이나 파라미터로 받지 않은 내부 property set은 어떻게 할까요?
Java와 비교해봅시다.
// Java
// Getter
Abbo abbo = new Abbo(...);
String auth = abbo.getAuth();
System.out.println(auth);
// Setter
abbo.setPassword("12345");
abbo.setAuthLevel(1);
// Kotlin
// Getter
val abbo = Abbo( ...)
val auth = abbo.auth
print(auth)
// Setter
abbo.password = if(isAdmin) "12345" else "23456"
abbo.authLevel = 1
값이 많은 것을 한 번에 set 할 때에는 이렇게 해도 됩니다.
// apply
val abbo = Abbo(...).apply {
password: if(isAdmin) "12345" else "23456"
authLevel: 1
}
// also
val abbo = Abbo(...).also {
password: if(isAdmin) "12345" else "23456"
authLevel: 1
}
// with
val abbo = Abbo(...)
with(abbo) {
password: if(isAdmin) "12345" else "23456"
authLevel: 1
}
.apply는 abbo 객체를 전달받은 Scope에 블록이 생성되고 객체 자체를 리턴하는 성질이 있습니다.
.also는 this에 직접 접근하므로 데이터를 가지고 있게 됩니다.
with의 경우 block에서 사용될 객체가 생성될 때 사용합니다.
그 외에도 let, run, use 등의 함수가 있는데 여기서는 다루지 않고 간단히만 적어보겠습니다.
아래 링크는 기본 라이브러리에서 제공해주는 함수를 더 많고 자세하게 알려주셔서 도움이 되어 링크 남깁니다 :)
https://medium.com/@goinhacker/in-android-convert-java-to-kotlin-afe532fa7151
'Server' 카테고리의 다른 글
[Kotlin] MongoDB JPA 사용하기 (2) | 2020.06.30 |
---|---|
MongoDB 설치하기 (0) | 2020.06.30 |
Kotlin의 lateinit과 Nullable (2) (0) | 2020.06.30 |
Kotlin의 Any와 Nullable (1) (0) | 2020.06.29 |
Kotlin의 Control Flow (0) | 2020.06.26 |
Kotlin의 함수(Function) (0) | 2020.06.26 |