2022-03-08 작성완료
Data Classes는 값을 저장하는 클래스를 생성하기 쉽게 만든다. 이런 클래스들은 자동으로 복사, 문자열 표현 획득, collections에서의 인스턴스 사용을 위한 메서드를 제공한다. 이 메서드들을 클래스 선언 내에서 구현해 오버라이딩 할 수 있다.
data class User(val name: String, val id: Int) { // 1
override fun equals(other: Any?) =
other is User && other.id == this.id // 2
}
fun main() {
val user = User("Alex", 1)
println(user) // 3
val secondUser = User("Alex", 1)
val thirdUser = User("Max", 2)
println("user == secondUser: ${user == secondUser}") // 4
println("user == thirdUser: ${user == thirdUser}")
// hashCode() function
println(user.hashCode()) // 5
println(secondUser.hashCode())
println(thirdUser.hashCode())
// copy() function
println(user.copy()) // 6
println(user === user.copy()) // 7
println(user.copy("Max")) // 8
println(user.copy(id = 3)) // 9
println("name = ${user.component1()}") // 10
println("id = ${user.component2()}")
}
data
수정자로 data class를 정의한다.id
를 가질 경우 동일하다고 선언함으로써 equals
메서드를 오버라이딩한다.toString
메서드는 자동으로 생성되고, 이것이 println
아웃풋을 보기 좋게 한다.equals
는 아이디가 같다면 두 인스턴스가 동일하다고 취급한다.hashCode
를 가진다.copy
함수는 새 인스턴스를 만들기 쉽게 한다.copy
는 새 인스턴스를 생성한다. 그러므로 객체와 그 카피는 별개의 참조를 가진다.copy
는 클래스 생성자와 같은 순서로 아규먼트를 받아들인다.copy
를 명명된 아규먼트와 함께 사용해 프로퍼티 순서와 상관 없이 값을 바꿀 수 있다.componentN
함수는 선언 순서대로 값을 얻을 수 있게 해 준다. Enum classes는 고유 값들의 유한 집합을 표현하는 타입을 모델링하는데에 사용된다(예: 방향, 상태, 모드).
enum class State {
IDLE, RUNNING, FINISHED // 1
}
fun main() {
val state = State.RUNNING // 2
val message = when (state) { // 3
State.IDLE -> "It's idle"
State.RUNNING -> "It's running"
State.FINISHED -> "It's finished"
}
println(message)
}
when
표현식이 철저해서 else
-case 가 필요하지 않은지를 컴파일러가 추론할 수 있다.열거형은 다른 클래스들과 마찬가지로 프로퍼티와 메서드들을 가질 수 있다. 이들은 세미콜론을 통해 열거형 상수와 분리된다.
enum class Color(val rgb: Int) { // 1
RED(0xFF0000), // 2
GREEN(0x00FF00),
BLUE(0x0000FF),
YELLOW(0xFFFF00);
fun containsRed() = (this.rgb and 0xFF0000 != 0) // 3
}
fun main() {
val red = Color.RED
println(red) // 4
println(red.containsRed()) // 5
println(Color.BLUE.containsRed()) // 6
println(Color.YELLOW.containsRed()) // 7
}
toString
이 상수의 이름을 반환한다. 여기서는 RED
이다. RED
와 YELLOW
의 RGB 값이 첫 비트들(FF)를 공유하므로 true
를 출력한다.Sealed Classes는 상속을 제한할 수 있도록 한다. 클래스를 sealed로 선언하면
sealed class가 선언된 패키지의 서브패키지에서만 서브클래싱 할 수 있다. sealed class가 선언된 패키지 외부에서는 서브클래싱 할 수 없다.
sealed class Mammal(val name: String) // 1
class Cat(val catName: String) : Mammal(catName) // 2
class Human(val humanName: String, val job: String) : Mammal(humanName)
fun greetMammal(mammal: Mammal): String {
when (mammal) { // 3
is Human -> return "Hello ${mammal.name}; You're working as a ${mammal.job}" // 4
is Cat -> return "Hello ${mammal.name}" // 5
} // 6
}
fun main() {
println(greetMammal(Cat("Snowy")))
}
when
표현식에서 아규먼트로 사용한다.Mammal
이 Human
으로 캐스팅된다.Mammal
이 Cat
으로 캐스팅된다.else
케이스가 필요하지 않다. non-sealed superclass를 가지면 else
가 필수적이다.코틀린의 클래스와 오브젝트는 대부분의 객체지향 언어와 동일한 방식으로 동작한다: 클래스는 청사진이고, 객체는 클래스의 인스턴스이다. 대개 클래스를 정의하고 클래스로부터 여러 인스턴스를 생성한다:
import java.util.Random
class LuckDispatcher { //1
fun getNumber() { //2
var objRandom = Random()
println(objRandom.nextInt(90))
}
}
fun main() {
val d1 = LuckDispatcher() //3
val d2 = LuckDispatcher()
d1.getNumber() //4
d2.getNumber()
}
코틀린에는 object keyword가 있다. 이것은 단일 구현으로 데이터 타입을 얻기 위해 사용한다.
당신이 자바 유저이고 "single"이 무엇을 의미하는지 이해한다면 싱글톤 패턴을 생각할 수 있을 것이다. 이는 두 스레드가 인스턴스를 생성하려고 시도해도 오직 하나의 인스턴스만이 생성된다는 것을 보장한다.
이를 코틀린에서 사용하기 위해서는 object
를 선언하면 된다. 여기에는 클래스도 없고, 생성자도 없고, 오직 lazy instance만 있다. 오브젝트에 접근할 때 한 번만 생성되므로 이것은 lazy 하다. 접근하지 않으면 생성되지조차 않는다.
object
표현식여기 object
표현식의 기본적이고 전형적인 사용법이 있다. 간단한 오브젝트 프로퍼티 스트럭처를 만드는 것이다. 이것은 클래스 선언에서 할 필요가 없다. 단일 오브젝트를 생성하고, 그 멤버들을 선언하고, 한 함수 내부에서 그것에 접근하면 된다. 이와 같은 오브젝트는 종종 자바에서 익명 함수 인스턴스로 생성된다.
fun rentPrice(standardDays: Int, festivityDays: Int, specialDays: Int): Unit { //1
val dayRates = object { //2
var standard: Int = 30 * standardDays
var festivity: Int = 50 * festivityDays
var special: Int = 100 * specialDays
}
val total = dayRates.standard + dayRates.festivity + dayRates.special //3
print("Total price: $$total") //4
}
fun main() {
rentPrice(10, 2, 1) //5
}
object
선언object
선언 또한 사용할 수 있다. 이것은 표현식이 아니고, 변수 할당에 사용될 수 없다. 멤버에 직접 접근하기 위해 이것을 사용해야 한다.
object DoAuth { //1
fun takeParams(username: String, password: String) { //2
println("input Auth parameters = $username:$password")
}
}
fun main(){
DoAuth.takeParams("foo", "qwerty") //3
}
클래스 내부에서의 오브젝트 선언은 또 다른 유용한 케이스를 정의한다: 동반자 객체이다. 문법적으로 이것은 자바의 static 메서드와 유사하다: qualifier로써 클래스 이름을 사용해 오브젝트 멤버를 호출할 수 있다. 코틀린에서 동반자 객체를 사용할 계획이 있다면 패키지 수준 함수 사용을 고려해 보자.
class BigBen { //1
companion object Bonger { //2
fun getBongs(nTimes: Int) { //3
for (i in 1 .. nTimes) {
print("BONG ")
}
}
}
}
fun main() {
BigBen.getBongs(12) //4
}