404 Not Found

404 Not Found


nginx

Kotlin Inheritance and Interfaces Explained

Kotlin's inheritance model is safer than Java's: classes are final by default and methods are non-overridable by default — Charlie must explicitly declare open to allow inheritance, with the compiler guarding polymorphism safety.

1. What You'll Learn


2. An Architect's Real Story

(1) Pain Point: Accidental Override Causing Production Incidents

Bob inherited the Order class to create SpecialOrder and accidentally overrode the calculateTotal method — causing 500 special orders with incorrect amounts. The finance team raised an urgent alert.

(2) Kotlin's Compile-Time Guard

KOTLIN
// Java: override annotation is optional - silent override possible
class SpecialOrder extends Order {
    double calculateTotal() { ... }  // Silently overrides!
}

// Kotlin: override is MANDATORY - compiler catches mistakes
open class Order {
    open fun calculateTotal(): Double = ...
}
class SpecialOrder : Order() {
    override fun calculateTotal(): Double = ...  // Must declare override
}

override mandatory annotation + classes final by default = compiler guards inheritance safety. Bob will never accidentally override again.


3. Open Inheritance Model

(1) Classes Final by Default

KOTLIN
// Default: class is final (cannot be inherited)
class Order(val id: String)  // Cannot be extended

// Open: explicitly allow inheritance
open class Order(val id: String) {
    // Methods are also final by default
    fun process() { }  // Cannot be overridden

    // Open method: explicitly allow override
    open fun calculateTotal(): Double = 0.0
}

// Abstract: must be inherited, cannot be instantiated
abstract class BaseOrder(val id: String) {
    // Abstract method: must be implemented by subclass
    abstract fun calculateTotal(): Double

    // Concrete method in abstract class
    fun getId(): String = id
}

(2) Inheritance Modifier Hierarchy

Modifier Class Method Instantiable Inheritable Overridable
Default (final)
open
abstract ✅ (must) ✅ (must)

(3) Java vs Kotlin Inheritance Comparison

Dimension Java Kotlin
Class default Inheritable final (non-inheritable)
Method default Overridable final (non-overridable)
Override annotation @Override (optional) override (mandatory)
Open inheritance No declaration needed open explicit declaration
Design philosophy "Open by default" "Closed by default"

4. Interfaces and Default Implementations

(1) Interface Definition

KOTLIN
interface Discountable {
    // Abstract method
    fun discountRate(): Double

    // Default implementation
    fun applyDiscount(total: Double): Double {
        return total * (1.0 - discountRate())
    }
}

interface Trackable {
    val trackingCode: String?  // Abstract property

    fun track(): String = trackingCode?.let { "Tracking: $it" } ?: "Not shipped"
}

// Implement multiple interfaces
class PremiumOrder(
    val id: String,
    val total: Double,
    override val trackingCode: String?
) : Discountable, Trackable {
    override fun discountRate() = 0.15  // 15% discount
}

(2) Interface vs Abstract Class

Dimension Interface Abstract Class
Constructor None Has
State None (only abstract properties) Has (concrete properties)
Multiple inheritance Supported (multiple implements) Not supported (single inherits)
Default implementation Kotlin supported Supported
Use case Behavior contract Shared state + behavior

5. override Mandatory Annotation

(1) Basic Usage

KOTLIN
open class Order(val id: String, var status: String) {
    open fun summary(): String = "Order $id: $status"
}

class BulkOrder(id: String, status: String, val minQuantity: Int) : Order(id, status) {
    // MUST use override keyword
    override fun summary(): String = "Bulk $id: $status (min: $minQuantity)"
}

(2) Preventing Further Override

KOTLIN
open class Order {
    open fun process() { }
}

class SpecialOrder : Order() {
    // Prevent further override in subclasses
    final override fun process() { }
}

6. Multiple-Inheritance Conflict Resolution

(1) Diamond Inheritance Problem

KOTLIN
interface A {
    fun hello() = "A"
}

interface B {
    fun hello() = "B"
}

// Diamond: C inherits hello() from both A and B
class C : A, B {
    // MUST override to resolve conflict
    override fun hello(): String {
        // Explicitly choose which parent's implementation
        return super<A>.hello()  // Choose A's implementation
    }
}

(2) Conflict Resolution Strategies

KOTLIN
class D : A, B {
    override fun hello(): String {
        // Strategy 1: Pick one parent
        return super<B>.hello()

        // Strategy 2: Combine both
        // return "${super<A>.hello()} + ${super<B>.hello()}"

        // Strategy 3: Custom implementation
        // return "D"
    }
}

(3) Conflict Resolution Comparison

Strategy Syntax Use Case
Choose parent A super<A>.hello() A's implementation is more appropriate
Choose parent B super<B>.hello() B's implementation is more appropriate
Combine both super<A> + super<B> Need both behaviors
Custom implementation Custom code Neither is appropriate

7. Inheritance Hierarchy Diagram

100%
classDiagram
    class Order {
        +val id: String
        +var status: String
        +open fun summary(): String
        +open fun calculateTotal(): Double
    }
    class BulkOrder {
        +val minQuantity: Int
        +override fun calculateTotal(): Double
    }
    class PriorityOrder {
        +val priority: String
        +override fun summary(): String
    }
    class Discountable {
        <<interface>>
        +fun discountRate(): Double
        +fun applyDiscount(total: Double): Double
    }
    class Trackable {
        <<interface>>
        +val trackingCode: String?
        +fun track(): String
    }
    Order <|-- BulkOrder
    Order <|-- PriorityOrder
    BulkOrder ..|> Discountable
    PriorityOrder ..|> Trackable
    PriorityOrder ..|> Discountable

8. Complete Example: OrderProcessor Inheritance Hierarchy

KOTLIN
// ============================================
// OrderProcessor - Inheritance Hierarchy
// Feature: Order / BulkOrder / PriorityOrder
// ============================================

interface Discountable {
    fun discountRate(): Double
    fun applyDiscount(total: Double): Double = total * (1.0 - discountRate())
}

interface Trackable {
    val trackingCode: String?
    fun track(): String = trackingCode?.let { "Tracking: $it" } ?: "Not shipped yet"
}

open class Order(val id: String, var status: String, val total: Double) {
    init {
        require(total >= 0) { "Total must be non-negative" }
    }

    open fun summary(): String = "Order $id | \$$total USD | $status"
    open fun calculateFinal(): Double = total
}

class BulkOrder(
    id: String,
    status: String,
    total: Double,
    val minQuantity: Int
) : Order(id, status, total), Discountable {

    override fun discountRate() = 0.10  // 10% bulk discount

    override fun calculateFinal(): Double = applyDiscount(total)

    override fun summary(): String =
        "${super.summary()} | Bulk (min: $minQuantity) | Final: \$${calculateFinal()} USD"
}

class PriorityOrder(
    id: String,
    status: String,
    total: Double,
    val priority: String,
    override val trackingCode: String?
) : Order(id, status, total), Discountable, Trackable {

    override fun discountRate() = when (priority) {
        "VIP" -> 0.20
        "GOLD" -> 0.15
        else -> 0.05
    }

    override fun calculateFinal(): Double = applyDiscount(total)

    override fun summary(): String =
        "${super.summary()} | Priority: $priority | ${track()} | Final: \$${calculateFinal()} USD"
}

fun main() {
    val orders = listOf(
        Order("ORD-001", "CONFIRMED", 299.99),
        BulkOrder("ORD-002", "CONFIRMED", 5_000.00, 100),
        PriorityOrder("ORD-003", "SHIPPED", 15_000.00, "VIP", "TRK-XYZ789"),
        PriorityOrder("ORD-004", "PENDING", 2_500.00, "GOLD", null)
    )

    println("=== Order Summary ===")
    orders.forEach { println(it.summary()) }

    val totalSavings = orders
        .filterIsInstance<Discountable>()
        .sumOf { it.applyDiscount((it as Order).total) - (it as Order).calculateFinal() }

    println("\nTotal savings from discounts: \$$totalSavings USD")
}

Output:

TEXT
=== Order Summary ===
Order ORD-001 | $299.99 USD | CONFIRMED
Order ORD-002 | $5000.0 USD | CONFIRMED | Bulk (min: 100) | Final: $4500.0 USD
Order ORD-003 | $15000.0 USD | SHIPPED | Priority: VIP | Tracking: TRK-XYZ789 | Final: $12000.0 USD
Order ORD-004 | $2500.0 USD | PENDING | Priority: GOLD | Not shipped yet | Final: $2125.0 USD

Total savings from discounts: $3475.0 USD

❓ FAQ

Q Why are Kotlin classes final by default?
A Effective Java recommends "design and document for inheritance, or prohibit it." Kotlin adopts this advice, defaulting to prohibit inheritance, using open for explicit opening.
Q Can interfaces have constructors?
A No. Interfaces have no constructors and cannot hold state. Use abstract classes for shared state.
Q Can a class resolve conflicts when implementing multiple interfaces with default methods?
A Yes. If two interfaces have default methods with the same name and signature, the subclass must override the method and use super<InterfaceName> to choose an implementation.
Q Can override be omitted?
A No. Kotlin mandates the override keyword — omitting it causes a compile error. This is the key safety mechanism preventing accidental overrides.
Q Do abstract class methods need open?
A No. Abstract methods in abstract classes are implicitly overridable (must be overridden). Non-abstract open methods still need the open modifier.
Q Does Kotlin support calling super like Java?
A Yes. Subclass constructors use super(...) to call the parent constructor, methods use super.foo() to call the parent implementation, and interfaces use super<Interface>.foo().

📖 Summary


📝 Exercises

  1. Beginner (⭐): Define an Order and a BulkOrder inheriting from it, overriding the summary method. Hint: open class Order, class BulkOrder : Order()
  2. Intermediate (⭐⭐): Create Discountable and Trackable interfaces, have PriorityOrder implement both, resolving a name conflict. Hint: super<Discountable>
  3. Challenge (⭐⭐⭐): Design a complete order inheritance hierarchy: BaseOrderBulkOrder / PriorityOrder, each implementing different discount and shipping strategies. Hint: combine interfaces and abstract classes

← Previous | Next →

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏