Inheritance Modifiers (final, open, abstract)

About

Kotlin์˜ ์ƒ์†๋ณ€๊ฒฝ์ž์ธ final, open, abstract์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณธ๋‹ค.

์ƒ์†(Inheritance)์ด๋ž€

์ƒ์†์€ ๊ธฐ์กด์˜ ํด๋ž˜์Šค๋ฅผ ์žฌ์‚ฌ์šฉํ•ด ์ž์‹ ํด๋ž˜์Šค๊ฐ€ ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๋ฉค๋ฒ„๋ฅผ ๋ฌผ๋ ค๋ฐ›๋Š” ๊ฒƒ์„ ๋œปํ•œ๋‹ค. Java์—์„œ ์ƒ์†์€ extends ํ‚ค์›Œ๋“œ๋ฅผ ์ด์šฉํ•ด ๊ฐ€๋Šฅํ–ˆ๋‹ค.

class Parent {}
class Child extends Parent {}

์ƒ์†์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŠน์ง•์ด ์žˆ๋‹ค.

  • ์ƒ์†์€ ๊ธฐ์กด์— ๋งŒ๋“ค์–ด ๋†“์€ ํด๋ž˜์Šค์˜ ์žฌ์‚ฌ์šฉ, ํ™•์žฅ์„ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.

  • Java์—์„œ๋Š” ๋‹จ์ผ ์ƒ์†๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค.

  • ๋ถ€๋ชจ(super), ์ž์‹(sub)ํด๋ž˜์Šค๊ฐ€ ์กด์žฌํ•œ๋‹ค. ๊ฐ๊ฐ ๊ธฐ๋ฐ˜(base), ํŒŒ์ƒ(derived) ํด๋ž˜์Šค๋ผ๊ณ ๋„ ๋ถ€๋ฅธ๋‹ค.

  • Java์—์„œ Object ํด๋ž˜์Šค๋Š” ๋ชจ๋“  ํด๋ž˜์Šค์˜ ์ตœ์ƒ์œ„์— ์œ„์น˜ํ•œ๋‹ค.

    • ๋ชจ๋“  ํด๋ž˜์Šค๋Š” Object ํด๋ž˜์Šค์— ์ •์˜๋œ 11๊ฐœ์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์ƒ์†๋ฐ›๋Š”๋‹ค. (toString(), equals(), hashCode() ๋“ฑ)

  • private ๋ฉค๋ฒ„ ๋ณ€์ˆ˜๋Š” ์ƒ์†์ด ์•ˆ๋œ๋‹ค.

  • super ํ‚ค์›Œ๋“œ๋ฅผ ์ด์šฉํ•ด ์ƒ์œ„ ํด๋ž˜์Šค์˜ ๋ฉค๋ฒ„/๋ฉ”์†Œ๋“œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

์ƒ์†์€ ๋” ์ •ํ™•ํžˆ ๋งํ•ด์„œ ๊ตฌํ˜„ ์ƒ์†(์„œ๋ธŒํด๋ž˜์‹ฑ)๊ณผ ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์†(์„œ๋ธŒํƒ€์ดํ•‘)์œผ๋กœ ๋ถ„๋ฅ˜ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ชฉ์ ์œผ๋กœ ์ƒ์†์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์„ ๊ตฌํ˜„ ์ƒ์†, ๋‹คํ˜•์ ์ธ ํ˜‘๋ ฅ์„ ์œ„ํ•ด ๋ถ€๋ชจ ํด๋ž˜์Šค์™€ ์ž์‹ ํด๋ž˜์Šค๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ƒ์†์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ์„ ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์†์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. <์˜ค๋ธŒ์ ํŠธ>(์œ„ํ‚ค๋ถ์Šค, 2019)

Java์™€ ์ƒ์†

Java์—์„œ ํด๋ž˜์Šค๋Š” ๊ธฐ๋ณธ ์„ค์ •์œผ๋กœ ๋ชจ๋‘ ์ƒ์†์ด ๊ฐ€๋Šฅํ–ˆ์œผ๋ฉฐ, ํด๋ž˜์Šค ์•ž์— final ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด๋ฉด ์ƒ์†์„ ๋ง‰์„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

public final class NotInheritable {
    // ... Class contents
}

๊ฐ์ฒด์ง€ํ–ฅ์ ์ธ ๊ด€์ ์—์„œ ์ทจ์•ฝํ•œ ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค(fragile base class) ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์ž์‹ ํด๋ž˜์Šค๋Š” ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๋ถˆํ•„์š”ํ•œ ์„ธ๋ถ€์‚ฌํ•ญ์— ์—ฎ์ด๊ฒŒ ๋œ๋‹ค. ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ์ž‘์€ ๋ณ€๊ฒฝ์—๋„ ์ž์‹ ํด๋ž˜์Šค๋Š” ์ปดํŒŒ์ผ ์˜ค๋ฅ˜์™€ ์‹คํ–‰ ์—๋Ÿฌ๋ผ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์ƒ์†์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜๋Š” ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ๊ทผ๋ณธ์ ์ธ ์ทจ์•ฝ์„ฑ์ด๋‹ค.

Kotlin๊ณผ ์ƒ์†

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Kotlin์—์„œ ํด๋ž˜์Šค๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ final์ด๋ฉฐ open์„ ํ†ตํ•ด ๋ฒ ์ด์Šค ํด๋ž˜์Šค๋กœ ๋งŒ๋“ค๋„๋ก ํ–ˆ๋‹ค.

์ƒ์†๋ณ€๊ฒฝ์ž๋Š” ์ด 3๊ฐ€์ง€๊ฐ€ ์กด์žฌํ•œ๋‹ค.

  1. final

  2. open

  3. abstract

final

์ƒ์†์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ์ƒ์†๋ณ€๊ฒฝ์ž์ด๋‹ค. ํด๋ž˜์Šค์˜ ๊ธฐ๋ณธ์ด๊ณ , ์ƒ๋žต์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

open

์ƒ์†์„ ํ—ˆ์šฉํ•œ๋‹ค.

abstract

์ธ์Šคํ„ด์Šคํ™” ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ƒ์†์„ ํ•ด์„œ ์ƒˆ๋กœ์šด ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค.

์ถ”์ƒ ํด๋ž˜์Šค๋ผ๊ณ  ํ•˜๋ฉฐ, ๊ณตํ†ต๋œ ์ฝ”๋“œ, ๋™์ž‘ ๋“ฑ์„ ์ •์˜ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

Spring ๊ฐœ๋ฐœํ•  ๋•Œ Kotlin๊ณผ ์ƒ์†

Spring Boot 2.x ๋ฒ„์ „๋ถ€ํ„ฐ๋Š” CGLIB Proxy ๋ฐฉ์‹์œผ๋กœ Bean์„ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ๋‹ค. CGLIB Proxy๋Š” target class๋ฅผ ์ƒ์†๋ฐ›์•„ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์†์ด ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์—ฌ์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ Kotlin์—์„œ๋Š” final ์ƒ์†๋ณ€๊ฒฝ์ž๊ฐ€ ํด๋ž˜์Šค์— ๊ธฐ๋ณธ์ ์œผ๋กœ ์ ์šฉ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ์ƒ์†์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ์ƒํƒœ๊ฐ€ ๋œ๋‹ค.

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํด๋ž˜์Šค์— ์ „๋ถ€ open์„ ๋ถ™์—ฌ ์ฃผ์–ด์•ผ ํ•˜๋Š”๋ฐ, ์ด๋Ÿฌํ•œ ์ž‘์—…์€ ๋งค์šฐ ๋ฒˆ๊ฑฐ๋กญ๋‹ค. Kotlin์—์„œ๋Š” ์ด๊ฒƒ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด all-open ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ œ๊ณตํ•œ๋‹ค.

plugins {
    kotlin("plugin.jpa") version "1.4.32"
}

plugin.spring ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์•„๋ž˜ ์–ด๋…ธํ…Œ์ด์…˜์— ๋Œ€ํ•ด all-open์„ ์ž๋™์œผ๋กœ ์ถ”๊ฐ€์‹œํ‚จ๋‹ค. kotlin-allopen, plugin.spring์€ ๋™์ผํ•œ ํ”„๋กœ์ ํŠธ์ด๋‹ค.

  • @Component

  • @Async

  • @Transactional

  • @Cacheable

  • @SpringBootTest

  • @Configuration, @Controller, @RestController, @Service, @Repository, (@Component๋กœ ๋ฉ”ํƒ€์–ด๋…ธํ…Œ์ด์…˜์ด ์ ์šฉ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ์ž๋™ ์ ์šฉ)

ํ•˜์ง€๋งŒ Spring์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ JPA๋„ ์‚ฌ์šฉํ•˜๊ณค ํ•˜๋Š”๋ฐ, JPA ์–ด๋…ธํ…Œ์ด์…˜์— ๋Œ€ํ•ด์„œ๋„ ๋ช…์‹œ๋ฅผ ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

// build.gradle.kts
allOpen {
    annotation("javax.persistence.Entity")
    annotation("javax.persistence.MappedSuperclass")
    annotation("javax.persistence.Embeddable")
}

์œ„์˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ allOpen์„ ๋ช…์‹œ์ ์œผ๋กœ ์ ์šฉํ•ด์•ผ @Entity ํด๋ž˜์Šค๊ฐ€ open์œผ๋กœ ์„ ์–ธ๋œ๋‹ค. open ์ƒ์†๋ณ€๊ฒฝ์ž๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š์œผ๋ฉด Proxy ๊ธฐ๋ฐ˜์œผ๋กœ Lazy ๋กœ๋”ฉ์„ ํ•  ์ˆ˜ ์—†๋‹ค.

@ManyToOne ๋“ฑ ๊ด€๊ณ„๋ฅผ ์„ค์ •ํ•˜๊ณ  fetch = FetchType.LAZY๋ฅผ ์ ์šฉํ–ˆ์„ ๋•Œ์˜ ์˜ˆ์‹œ์ด๋‹ค.

@Entity
class Book(
    @Column(nullable = false)
    val title: String,
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(nullable = false)
    val order: Order,
) : BaseEntity()

@Entity
class Order(
    @Column(nullable = false)
    val number: String,
) : BaseEntity()

๋‹ค์Œ์€ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์ด๋‹ค.

@Test
fun `lazy loading test`() {
    // Order, Book ์ƒ์„ฑ
    val order = orderRepository.save(Order("202208-01")
    val book = bookRepository.save(Book("New Book", order))
    
    // ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์ดˆ๊ธฐํ™”
    entityManager.clear()
    
    // Lazy Loading์ด ์ ์šฉ๋˜์–ด book์— ๋Œ€ํ•œ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์„ ๊ฑฐ๋ผ ์˜ˆ์ƒ
    val foundBook = bookRepository.findByIdOrNull(book.id!!)!!
}

Lazy ๋กœ์ด ์ ์šฉ๋˜์–ด book์— ๋Œ€ํ•œ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์„ ๊ฑฐ๋ผ ์˜ˆ์ƒํ–ˆ์ง€๋งŒ ๊ฒฐ๊ณผ๋Š” ๋‹ค๋ฅด๋‹ค.

order์— ๋Œ€ํ•œ ์กฐํšŒ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ์žˆ๋Š” ๋ชจ์Šต์ด๋‹ค. IntelliJ์˜ ๋””๋ฒ„๊น… ํˆด์„ ์ด์šฉํ•ด ํ™•์ธํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

Order์˜ Proxy ๊ฐ์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ ์‹ค์ œ Order ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๋ชจ์Šต์ด๋‹ค.

Kotlin์€ ๊ธฐ๋ณธ์ ์œผ๋กœ final์ด๋ฏ€๋กœ, ์ƒ์†์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘๋™ํ•˜๋Š” Proxy ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋”ฐ๋ผ์„œ open์„ ์ ์šฉํ•˜๋ฉด ์ œ๋Œ€๋กœ Lazy ๋กœ๋”ฉ์ด ๋™์ž‘ํ•˜๊ณ , Proxy ๊ธฐ๋ฐ˜์œผ๋กœ Order ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋œ๋‹ค.

โš ๏ธ ์œ„ ๋‚ด์šฉ์˜ ์ถœ์ฒ˜, ์ด๋ฏธ์ง€์™€ ์ž์„ธํ•œ ๋‚ด์šฉ ๋ชจ๋‘ ์ด ๋ธ”๋กœ๊ทธ๋ฅผ ์ฐธ๊ณ ํ•œ๋‹ค.

์ •๋ฆฌ

Java, Kotlin ๋‘˜ ๋‹ค ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฐœ๋…์ธ ์ƒ์†์„ ์ง€์›ํ•œ๋‹ค.

  • Java์—์„œ๋Š” abstract, final ๋“ฑ์˜ modifier๋กœ ์ƒ์† ๊ด€๋ จ ์„ค์ •์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ, ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ํด๋ž˜์Šค๊ฐ€ ์ƒ์†์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ final ํ‚ค์›Œ๋“œ๋ฅผ ์ง€์ •ํ•˜๋ฉด ์ƒ์†์„ ๋ง‰์„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

  • Kotlin์—์„œ๋Š” ์ƒ์†๋ณ€๊ฒฝ์ž์ธ final, open, abstract๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. final์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ํ•˜์—ฌ ์ƒ์†์„ ๋ง‰์•„๋‘์—ˆ๋‹ค.

  • Spring๊ณผ Kotlin์„ ๊ฐ™์ด ์‚ฌ์šฉํ•  ๋•Œ๋Š” CGLIB์„ ์ด์šฉํ•œ Proxy ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™”ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Kotlin์—์„œ ๊ธฐ๋ณธ๊ฐ’์ด final์ธ ์ ์„ ๊ฐ์•ˆํ•˜์—ฌ allopen ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ ์šฉํ•ด์•ผ ํ•œ๋‹ค.

More

REF

Last updated