상속(Inheritance)
- kotlin : finall(default), 즉 상속 불가
- class, method, member variable 모두 적용
- 단일 상속, 복수 인터페이스
- open : 상속 가능하도록 지정하는 키워드
subClass : parentClass()subClass : interface
- parent → child 인스턴스화
- 이 때 child의 parmeter → parent로 전달 가능
open class paretClass {
...
}
class childCalss : parentClass() {
...
}
class childCalss(value: String) : parentClass(value) { // parameters 전달
...
}
- 멤버 변수 및 메소드의 경우 class scope을 가짐
this(self-reference variable, 자기 자신 참조 변수) 없이 접근 가능
open class Parent {
var hello: String = "hell"
fun sayHello() {
println("parent $hello")
}
}
class Child : Parent() {
fun childHello() {
println("상속 받은 child $hello")
hello = "o"
sayHello() // parent method
}
}
fun main() {
val child = Child()
child.sayHello()
child.childHello()
}
>>>
parent hell
상속 받은 child hell
parent o
- 부모 클래스에 부 생성자 → super 키워드를 통해 상속 가능
class MyView : View {
constructor(ctx: Context) : super(ctx)
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}
상속 제어 변경자
- final : override 금지
- open : override 가능
- abstract : override 강제, 선언만 존재
- overloading 구현 가능
| Modifier | Corresponding member | Comments |
|---|---|---|
| final | Can’t be overridden | Used by default for class members |
| open | Can be overridden | Should be specified explicitly |
| abstract | Must be overridden | Can be used only in abstract classes; abstract members can’t have an implementation |
| override | Overrides a member in a superclass or interface | Overridden member is open by default, if not marked final |
abstract class Animated { // 이 클래스는 추상클래스다. 이 클래스의 인스턴스를 만들 수 없다.
abstract fun animate() // 이 함수는 추상 함수다. 이 함수에는 구현이 없다. 하위 클래스에서는 이 함수를 반드시 오버라이드해야 한다.
open fun stopAnimating() { ... } // 추상 클래스에 속했더라도 비추상 함수는 기본적으로 파이널이지만 원한다면 open으로 오버라이드를 허용할 수 있다.
fun animateTwice() { ... } // 추상 클래스에 속했더라도 비추상 함수는 기본적으로 파이널이지만 원한다면 open으로 오버라이드를 허용할 수 있다.
}
Override
override fun parentMethod(...) {...}super: parent-reference variable- kotlin : getter/setter 자동 생성
override: getter/setter 재정의
- 권한의 확장 가능
val→varO, ← X
open class Shape {
open val name = "poly"
open fun draw() { /*...*/ }
fun fill() { /*...*/ }
}
class Circle() : Shape() {
override var name = "circle"
override fun draw() {
super.draw()
/*...*/
}
}
open class Shape(vertex: Int?) {
open val vertex: Int? = vertex
fun getVertexNum() {
println("vertex : $vertex")
}
}
class Circle(vertex: Int? = null) : Shape(vertex) {
override val vertex = null
}
fun main() {
val circle = Circle(1)
println(circle.vertex)
circle.getVertexNum()
}
데이터 클래스
- 데이터를 저장하기 위한 용도의 클래스
data class className(val/var property1, ...)- parameter 생략 불가
- 메소드 기본 생성 :
equals,hashCode,toString,copy,componentN등
data class Person(val name: String, var age: Int)
fun main() {
val p1 = Person("p1", 500)
val p2 = p1.copy("p2")
val p3 = p1.copy("p3", 900)
val p1_1 = p1.copy()
val p1_2 = p1
println(p1.component1()) // p1
println(p1.component2()) // 500
println(p1.toString()) // Person(name=p1, age=500)
println(p3) // Person(name=p3, age=900)
println(p1.equals(p1_1)) // true
println(p1 == p1_1) // true
println(p1 === p1_1) // false
println(p1 === p1_2) // true
}
Sealed class
- 상속 가능한 클래스의 종류를 제한 → 안전한 계층 구조를 설계
- when 식에서 모든 하위 클래스가 처리되었는지 컴파일러가 확인 가능 (else 불필요)
- Sealed class 의 하위 클래스 : 클래스, 데이터 클래스, object 등 정의 가능
object: single tone
- sealed class 는 추상 클래스의 특징 + 상속 제한을 가진 특별한 추상 클래스(추상 메서드 선언 가능)
- class 등을 변수로 설정하여 duck typing을 실행
sealed class Expr {
class Num(val value: Int) : Expr()
class Sum(val left: Expr, val right: Expr) : Expr()
}
fun eval(e: Expr): Int =
when (e) {
is Expr.Num -> e.value
is Expr.Sum -> eval(e.right) + eval(e.left)
}
---
sealed class ApiResult
data class Success(val data: String): ApiResult()
data class Failure(val error: String): ApiResult()
object Loading: ApiResult()
fun handleResult(result: ApiResult) =
when (result) {
is Success -> println("성공 : ${result.data}")
is Failure -> println("실패 : ${result.error}")
Loading -> println("Loading")
}
fun main() {
handleResult(Success("get data")) // 성공 : get data
handleResult(Failure("404")) // 실패 : 404
handleResult(Loading) // Loading
}

sealed class Error(val message: String) {
class NetworkError : Error("Network failure")
class DatabaseError : Error("Database cannot be reached")
class UnknownError : Error("An unknown error has occurred")
}
fun main() {
val errors = listOf(Error.NetworkError(), Error.DatabaseError(), Error.UnknownError())
errors.forEach { println(it.message) }
}
// Network failure
// Database cannot be reached
// An unknown error has occurred
- sealed interface : request(input) → sealde class : response(output)
// Import necessary modules
import io.ktor.server.application.*
import io.ktor.server.resources.*
import kotlinx.serialization.*
// Define the sealed interface for API requests using Ktor resources
@Resource("api")
sealed interface ApiRequest
@Serializable
@Resource("login")
data class LoginRequest(val username: String, val password: String) : ApiRequest
@Serializable
@Resource("logout")
object LogoutRequest : ApiRequest
// Define the ApiResponse sealed class with detailed response types
sealed class ApiResponse {
data class UserSuccess(val user: UserData) : ApiResponse()
data object UserNotFound : ApiResponse()
data class Error(val message: String) : ApiResponse()
}
// User data class to be used in the success response
data class UserData(val userId: String, val name: String, val email: String)
// Function to validate user credentials (for demonstration purposes)
fun isValidUser(username: String, password: String): Boolean {
// Some validation logic (this is just a placeholder)
return username == "validUser" && password == "validPass"
}
// Function to handle API requests with detailed responses
fun handleRequest(request: ApiRequest): ApiResponse {
return when (request) {
is LoginRequest -> {
if (isValidUser(request.username, request.password)) {
ApiResponse.UserSuccess(UserData("userId", "userName", "userEmail"))
} else {
ApiResponse.Error("Invalid username or password")
}
}
is LogoutRequest -> {
// Assuming logout operation always succeeds for this example
ApiResponse.UserSuccess(UserData("userId", "userName", "userEmail")) // For demonstration
}
}
}
// Function to simulate a getUserById call
fun getUserById(userId: String): ApiResponse {
return if (userId == "validUserId") {
ApiResponse.UserSuccess(UserData("validUserId", "John Doe", "john@example.com"))
} else {
ApiResponse.UserNotFound
}
// Error handling would also result in an Error response.
}
// Main function to demonstrate the usage
fun main() {
val loginResponse = handleRequest(LoginRequest("user", "pass"))
println(loginResponse)
val logoutResponse = handleRequest(LogoutRequest)
println(logoutResponse)
val userResponse = getUserById("validUserId")
println(userResponse)
val userNotFoundResponse = getUserById("invalidId")
println(userNotFoundResponse)
}
클래스 확장
- 기존 클래스에 새로운 기능(메서드)을 추가
- 기존 클래스의 코드를 변경 X
fun className.extensionName(...) {...}
fun String.addPrefix(prefix: String): String = "$prefix$this"
fun main() {
println("Ultman".addPrefix("Sam ")) // Sam Ultman
}
예제
open class Parent {
open fun greet() = println("hello")
}
class Child : Parent() {
override fun greet() = println("no thanks")
}
fun main() {
val child = Child()
child.greet()
}
open class Animal {
open var age: Int = 0
}
class Cat : Animal() {
override var age: Int = 200
}
fun main() {
val cat = Cat()
println(cat.age)
}
fun Int.isOdd() = this%2 != 0
fun main() {
println(7.isOdd())
}
data class Book(val title: String, val author: String)
fun main() {
val book = Book("LOL", "ALL")
val hook = book.copy("WOW", "LOW")
println(book.equals(hook))
}
sealed class Transport
data class Car(val home: String): Transport()
data class Train(val range: String): Transport()
data class Airplane(val contry: String): Transport()
fun where2Go(T: Transport) =
when(T) {
is Car -> println("go home : ${T.home}")
is Train -> println("work : ${T.range}")
is Airplane -> println("vacation : ${T.contry}")
}
fun main() {
where2Go(Car("hawai"))
where2Go(Train("LA"))
where2Go(Airplane("Alaska"))
}
---
sealed class Transport{
data class Car(val home: String): Transport()
data class Train(val range: String): Transport()
data class Airplane(val contry: String): Transport()
}
fun where2Go(T: Transport): Unit {
return when(T) {
is Transport.Car -> println("go home : ${T.home}")
is Transport.Train -> println("work : ${T.range}")
is Transport.Airplane -> println("vacation : ${T.contry}")
}
}
fun main() {
where2Go(Transport.Car("hawai")) // go home : hawai
where2Go(Transport.Train("LA")) // work : LA
where2Go(Transport.Airplane("Alaska")) // vacation : Alaska
}
C
Contents
