data class User(val name: String, val age: Int)
fun main() {
val user1 = User("John", 30)
val user2 = User("John", 30)
val user3 = User("Sarah", 25)
println(user1) // User(name=John, age=30)
println(user1 == user2) // true
println(user1 == user3) // false
println(user1.hashCode()) // 1524964254
println(user2.hashCode()) // 1524964254
println(user3.hashCode()) // 135747841
}
다음 예제는 data class를 명시적으로 프로퍼티를 선언하고, 초기화하는 방법입니다.
data class Person(var name: String = "", var age: Int = 0)
object Logger {
fun log(message: String) {
println("LOG: $message")
}
}
fun main() {
Logger.log("Hello, world!") // LOG: Hello, world!
}
위 코드에서 object 클래스를 사용하여 Logger 객체를 만들었습니다.
Logger 객체는 전역 객체이므로, 객체 생성 없이 Logger.log("Hello, world!")와 같이 객체에 접근할 수 있습니다.
log() 메서드는 객체의 메서드로, 인자로 받은 메시지를 출력합니다.
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF)
}
위 예시에서는 Color라는 enum class를 정의하고, RED, GREEN, BLUE 세 개의 상수 값을 가지도록 하였습니다.
이제, 이 enum class를 사용하여 다음과 같이 색상을 출력할 수 있습니다.
fun main() {
val red = Color.RED
println("red: ${red.rgb}") // red: 16711680
}
위 예시에서 val red = Color.RED는 RED 상수 값을 변수 red에 할당하는 것을 의미합니다.
이후 red.rgb는 red 변수의 rgb 프로퍼티 값을 출력하는 것입니다.
enum class Color {
RED,
GREEN,
BLUE
}
fun main() {
val red = Color.RED
val green = Color.GREEN
val blue = Color.BLUE
println(red.ordinal) // 0
println(green.ordinal) // 1
println(blue.ordinal) // 2
println(red.name) // RED
println(green.name) // GREEN
println(blue.name) // BLUE
}
위 예시에서 Color enum class는 RED, GREEN, BLUE 세 개의 상수 값을 가집니다.
red.ordinal, green.ordinal, blue.ordinal은 각 상수 값의 순서를 나타내는데, RED는 0번째, GREEN은 1번째, BLUE는 2번째에 위치하므로 각각 0, 1, 2가 출력됩니다.
red.name, green.name, blue.name은 각 상수 값의 이름을 나타내는데, RED, GREEN, BLUE의 이름을 가지므로 각각 "RED", "GREEN", "BLUE"가 출력됩니다.
sealed class는 코틀린에서 추상화된 클래스 타입 중 하나로, 특정 클래스 타입을 상속받은 하위 클래스들을 제한하는 용도로 사용됩니다. 즉, sealed class는 해당 클래스를 상속하는 하위 클래스들을 제한하고, 제한된 하위 클래스들 중 하나를 나타내는 값을 갖는 클래스 타입을 선언하는 데 사용됩니다.
sealed class는 다음과 같은 특징을 가집니다.
sealed class는 abstract 클래스입니다. 따라서 sealed class 타입의 인스턴스를 직접 생성할 수는 없습니다.
sealed class는 하위 클래스를 선언할 때, 해당 클래스를 선언한 파일 내에서만 선언할 수 있습니다.
즉, sealed class의 하위 클래스는 그 클래스를 선언한 파일 내에서만 선언할 수 있습니다.
sealed class의 하위 클래스는 data class, enum class, interface, class 등 어떤 클래스 타입이던 상관 없습니다.
sealed class는 when 표현식과 함께 사용할 때 유용합니다. when 표현식에서 sealed class의 모든 하위 클래스에 대한 분기를 처리하면, else 분기를 사용하지 않아도 컴파일러가 모든 가능한 경우를 체크하도록 보장합니다.
sealed class Result<out T> {
data class Success<T>(val data: T) : Result<T>()
data class Failure(val error: Throwable) : Result<Nothing>()
object Loading : Result<Nothing>()
}
fun handleResult(result: Result<Int>) {
when (result) {
is Result.Success -> {
val data = result.data
// handle success case
}
is Result.Failure -> {
val error = result.error
// handle failure case
}
Result.Loading -> {
// handle loading case
}
}
}
위 코드에서 ConnectionState는 sealed class로 정의되어 있습니다.
Connected, Connecting, Error 세 개의 하위 클래스를 가지고 있습니다.
Connected와 Connecting 하위 클래스는 object로 정의되어 있으며, Error 하위 클래스는 data class로 정의되어 있습니다.
handleConnectionState 함수에서 when 표현식을 사용하여 ConnectionState 클래스의 모든 하위 클래스에 대한 분기를 처리하고 있습니다.
이렇게 하면, ConnectionState 클래스의 모든 하위 클래스에 대한 처리를 안전하게 보장할 수 있습니다.
Kotlin에서 내부 클래스(Inner class)는 다른 클래스 내부에 정의된 클래스입니다.
Java와 마찬가지로, 내부 클래스는 바깥 클래스의 멤버 변수와 메서드에 접근할 수 있습니다.
하지만, Kotlin에서는 Java와 달리 내부 클래스는 기본적으로 정적(static) 클래스로 생성되지 않습니다.
즉, 기본적으로 바깥 클래스의 인스턴스와 내부 클래스의 인스턴스는 서로 다릅니다.
다음은 Kotlin에서 내부 클래스를 정의하는 예제입니다.
class Outer {
private val outerValue: Int = 10
inner class Inner {
fun printOuterValue() {
println("outerValue: $outerValue")
}
}
}
위 예제에서 Outer 클래스 내부에 Inner 내부 클래스를 정의하고 있습니다.
Inner 클래스에서 Outer 클래스의 멤버 변수 outerValue에 접근하고 있습니다.
내부 클래스를 사용하기 위해서는, 내부 클래스의 인스턴스를 생성하기 위해 외부 클래스의 인스턴스를 먼저 생성해야 합니다.
예를 들어, 다음과 같이 사용할 수 있습니다.
val outer = Outer()
val inner = outer.Inner()
inner.printOuterValue()
위 예제에서는 먼저 Outer 클래스의 인스턴스를 생성하고, 그 다음에 Inner 클래스의 인스턴스를 생성하고 있습니다.
Inner 클래스의 인스턴스를 생성하기 위해서는 Outer 클래스의 인스턴스를 사용해야 하기 때문입니다.
내부 클래스는 바깥 클래스와 강한 결합을 갖고 있기 때문에, 내부 클래스를 사용하는 경우에는 메모리 누수 등의 문제가 발생할 수 있습니다.
따라서, 내부 클래스를 사용하기 전에 반드시 잘 고려해야 합니다.
📌중첩 클래스는 자신이 속한 외부 클래스의 인스턴스에 접근할 수 없습니다.
다음은 중첩 클래스와 내부 클래스를 사용하여 외부 클래스의 필드에 접근하는 예제입니다.
class Outer {
private val outerValue: Int = 10
class Nested {
fun printOuterValue() {
// 중첩 클래스에서는 외부 클래스의 필드에 접근할 수 없습니다.
//println("outerValue: $outerValue") // 컴파일 오류 발생
}
}
inner class Inner {
fun printOuterValue() {
println("outerValue: $outerValue")
}
}
}
fun main() {
val outer = Outer()
// 중첩 클래스에서는 외부 클래스의 인스턴스에 접근할 수 없습니다.
val nested = Outer.Nested()
//nested.printOuterValue() // 컴파일 오류 발생
// 내부 클래스에서는 외부 클래스의 인스턴스에 접근할 수 있습니다.
val inner = outer.Inner()
inner.printOuterValue() // 출력: outerValue: 10
}