Search
castle

상속(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 재정의
  • 권한의 확장 가능
    • valvar O, ← 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
}    

image.png


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
}
left
right

C

Contents