0
0
Kotlinprogramming~15 mins

Enum with properties and methods in Kotlin - Deep Dive

Choose your learning style9 modes available
Overview - Enum with properties and methods
What is it?
An enum in Kotlin is a special type that lets you define a fixed set of named values. Each value can have its own properties (like details or characteristics) and methods (actions it can perform). This helps group related constants with extra information and behavior in one place.
Why it matters
Enums with properties and methods make code clearer and safer by bundling data and behavior together. Without them, you might scatter related information across your code, making it harder to maintain and more error-prone. They help avoid mistakes like using invalid values or forgetting related details.
Where it fits
Before learning enums with properties and methods, you should understand basic Kotlin enums and classes. After this, you can explore sealed classes or advanced Kotlin features like data classes and interfaces to model complex data.
Mental Model
Core Idea
An enum with properties and methods is like a set of named objects, each carrying its own data and actions, grouped under one type.
Think of it like...
Imagine a deck of cards where each card is a unique object with its own suit and value, and can perform actions like showing its face or comparing itself to another card.
EnumType
╔════════════════════════╗
║  VALUE1 (property1)    ║
║  VALUE2 (property2)    ║
║  VALUE3 (property3)    ║
╚════════════════════════╝
Each value can call methods:
VALUE1.method() -> does something using its property
Build-Up - 7 Steps
1
FoundationBasic Kotlin Enum Definition
🤔
Concept: Learn how to define a simple enum with named constants.
enum class Direction { NORTH, SOUTH, EAST, WEST } fun main() { val dir = Direction.NORTH println(dir) // Prints the enum name }
Result
NORTH
Understanding the basic enum sets the stage for adding properties and methods later.
2
FoundationAdding Properties to Enum Values
🤔
Concept: Introduce properties to each enum value by defining a constructor and fields.
enum class Direction(val degrees: Int) { NORTH(0), SOUTH(180), EAST(90), WEST(270) } fun main() { println(Direction.EAST.degrees) // Access property }
Result
90
Knowing enums can hold data makes them more powerful than simple labels.
3
IntermediateDefining Methods Inside Enums
🤔
Concept: Add functions inside the enum class to perform actions using properties.
enum class Direction(val degrees: Int) { NORTH(0), SOUTH(180), EAST(90), WEST(270); fun isVertical() = this == NORTH || this == SOUTH } fun main() { println(Direction.NORTH.isVertical()) // true println(Direction.EAST.isVertical()) // false }
Result
true false
Embedding behavior inside enums keeps related logic close to the data it uses.
4
IntermediateOverriding Methods for Specific Enum Values
🤔
Concept: Customize behavior for individual enum constants by overriding methods.
enum class Operation { ADD { override fun apply(a: Int, b: Int) = a + b }, SUBTRACT { override fun apply(a: Int, b: Int) = a - b }; abstract fun apply(a: Int, b: Int): Int } fun main() { println(Operation.ADD.apply(5, 3)) // 8 println(Operation.SUBTRACT.apply(5, 3)) // 2 }
Result
8 2
Overriding methods per value allows each enum constant to behave uniquely.
5
IntermediateUsing Enum Properties and Methods Together
🤔
Concept: Combine properties and methods to create meaningful enum logic.
enum class Planet(val mass: Double, val radius: Double) { EARTH(5.97e24, 6371.0), MARS(0.642e24, 3389.5); fun surfaceGravity(): Double { val G = 6.67430e-11 return G * mass / (radius * radius * 1000 * 1000) // convert km to m } } fun main() { println("Earth gravity: ${Planet.EARTH.surfaceGravity()}") println("Mars gravity: ${Planet.MARS.surfaceGravity()}") }
Result
Earth gravity: 9.819973426224687 Mars gravity: 3.7126290961053403
Combining data and behavior in enums models real-world entities naturally.
6
AdvancedEnum Classes Implementing Interfaces
🤔Before reading on: Do you think enums can implement interfaces like classes? Commit to your answer.
Concept: Enums can implement interfaces to guarantee certain methods exist, enabling polymorphism.
interface Printable { fun printInfo() } enum class Color(val rgb: Int) : Printable { RED(0xFF0000) { override fun printInfo() = println("Red color") }, GREEN(0x00FF00) { override fun printInfo() = println("Green color") }; } fun main() { Color.RED.printInfo() // Red color Color.GREEN.printInfo() // Green color }
Result
Red color Green color
Knowing enums can implement interfaces unlocks flexible design patterns.
7
ExpertEnum Constructor Privacy and Reflection
🤔Before reading on: Do you think enum constructors can be called outside the enum class? Commit to your answer.
Concept: Enum constructors are private by design; you cannot create new enum instances at runtime, but reflection can inspect them.
enum class Status(val code: Int) { SUCCESS(0), ERROR(1) } fun main() { // Status(2) // Error: Cannot access constructor val values = Status.values() println(values.joinToString()) }
Result
SUCCESS, ERROR
Understanding enum constructor privacy explains why enums are fixed sets and how Kotlin enforces this.
Under the Hood
Kotlin compiles enums into classes with a fixed set of instances created at load time. Each enum constant is a singleton object with its own properties and methods. The enum class has a private constructor to prevent creating new instances outside the enum. Methods and properties are compiled as members of the enum class or overridden in anonymous subclasses for specific constants.
Why designed this way?
Enums are designed to represent fixed sets of constants safely and efficiently. Private constructors prevent accidental creation of invalid enum values. Allowing properties and methods inside enums makes them more expressive and closer to real-world modeling, avoiding scattered constants and logic.
EnumClass
╔════════════════════════╗
║ private constructor()  ║
║ ┌──────────────────┐  ║
║ │ VALUE1 instance  │  ║
║ │ VALUE2 instance  │  ║
║ │ VALUE3 instance  │  ║
║ └──────────────────┘  ║
║ methods & properties   ║
╚════════════════════════╝
Myth Busters - 4 Common Misconceptions
Quick: Can you create new enum values at runtime like normal objects? Commit to yes or no.
Common Belief:Enums are just like classes, so you can create new enum instances anytime you want.
Tap to reveal reality
Reality:Enum instances are fixed and created only once when the enum class loads; you cannot create new enum values at runtime.
Why it matters:Trying to create new enum values dynamically breaks the fixed set guarantee, leading to bugs and inconsistent program states.
Quick: Do all enum values share the same method implementations by default? Commit to yes or no.
Common Belief:All enum constants use the same methods unless you write separate functions outside the enum.
Tap to reveal reality
Reality:Each enum constant can override methods individually, allowing unique behavior per value.
Why it matters:Missing this leads to less flexible designs and forces clunky if-else checks outside the enum.
Quick: Does adding properties to enums make them mutable? Commit to yes or no.
Common Belief:Enums with properties can change their property values anytime like normal objects.
Tap to reveal reality
Reality:Enum properties are usually val (read-only) and enums are intended to be immutable singletons.
Why it matters:Assuming mutability can cause unexpected bugs and thread-safety issues.
Quick: Can enum constructors be public so you can create new instances? Commit to yes or no.
Common Belief:Enum constructors can be public like normal classes to allow flexible instantiation.
Tap to reveal reality
Reality:Enum constructors are always private or protected to prevent external instantiation.
Why it matters:This design enforces the fixed set of enum values and prevents accidental misuse.
Expert Zone
1
Enum constants with overridden methods are compiled as anonymous subclasses, which can affect performance and serialization.
2
Using interfaces with enums enables polymorphism but can complicate testing if not designed carefully.
3
Reflection can inspect enum properties and methods but cannot create new enum instances, preserving enum integrity.
When NOT to use
Avoid enums with properties and methods when the set of values is not fixed or needs to be extended dynamically; use sealed classes or regular classes instead.
Production Patterns
Enums with properties and methods are used for state machines, operation types, configuration keys, and modeling domain concepts with fixed variants and behavior.
Connections
Sealed Classes
Builds-on
Understanding enums with properties prepares you for sealed classes, which allow fixed sets with more flexible data and inheritance.
Object-Oriented Polymorphism
Same pattern
Enums overriding methods per constant is a form of polymorphism, showing how fixed sets can have varied behavior like subclasses.
Finite State Machines (Theory)
Application
Enums with properties and methods model states and transitions in finite state machines, a concept used in computer science and engineering.
Common Pitfalls
#1Trying to create new enum instances outside the enum class.
Wrong approach:val newStatus = Status(2) // Error: Cannot access constructor
Correct approach:Use predefined enum values like Status.SUCCESS or Status.ERROR only.
Root cause:Misunderstanding that enum constructors are private and enums represent fixed sets.
#2Mutating enum properties after creation.
Wrong approach:enum class Color(var rgb: Int) { RED(0xFF0000) } Color.RED.rgb = 0x00FF00 // Allowed but unsafe
Correct approach:enum class Color(val rgb: Int) { RED(0xFF0000) } // Use val for immutability
Root cause:Not using val for properties, leading to mutable enum instances which breaks enum safety.
#3Using if-else chains outside enums instead of overriding methods inside.
Wrong approach:fun apply(op: Operation, a: Int, b: Int): Int { return if (op == Operation.ADD) a + b else a - b }
Correct approach:enum class Operation { ADD { override fun apply(a: Int, b: Int) = a + b }, SUBTRACT { override fun apply(a: Int, b: Int) = a - b }; abstract fun apply(a: Int, b: Int): Int }
Root cause:Not leveraging enum polymorphism leads to scattered logic and harder maintenance.
Key Takeaways
Kotlin enums can hold properties and methods, making each constant a rich object with data and behavior.
Enum constructors are private, ensuring the set of enum values is fixed and safe.
Overriding methods per enum constant enables unique behavior without external conditionals.
Enums can implement interfaces, allowing flexible and polymorphic designs.
Misusing enums by trying to create new instances or mutating properties breaks their core guarantees.