Post

Kotlin Class Types

A quick overview of all class types in Kotlin, including regular classes, data classes, object declarations, sealed classes, abstract classes, and more—explaining their purpose and usage in concise terms.

Kotlin Class Types

Normal Class

A normal class is the most basic class type in Kotlin. It acts as a blueprint for creating objects and can contain properties, methods, and constructors.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Define a class
class Person(val name: String, var age: Int) {
    
    // Member function
    fun introduce() {
        println("Hi, I'm $name and I'm $age years old.")
    }
}

// Main function
fun main() {
    // Create an object (instance) of the class
    val person1 = Person("Tawhid", 22)

    // Access properties and methods
    println(person1.name)      // Output: Tawhid
    println(person1.age)       // Output: 22
    person1.introduce()        // Output: Hi, I'm Tawhid and I'm 22 years old.

    // Modify a mutable property
    person1.age = 23
    person1.introduce()        // Output: Hi, I'm Tawhid and I'm 23 years old.
}

Data Class

A data class is a special class in Kotlin used to hold data. It automatically provides useful functions like toString(), equals(), hashCode(), and copy().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Define a data class
data class User(
    val name: String,
    val email: String
)

// Main function
fun main() {
    // Create an object of the data class
    val user1 = User("Tawhid", "tawhid@email.com")

    // Access properties
    println(user1.name)        // Output: Tawhid
    println(user1.email)       // Output: tawhid@email.com

    // Use auto-generated toString()
    println(user1)             // Output: User(name=Tawhid, email=tawhid@email.com)

    // Create a copy with a modified value
    val user2 = user1.copy(email = "new@email.com")
    println(user2)             // Output: User(name=Tawhid, email=new@email.com)

    // Compare objects
    println(user1 == user2)    // Output: false
}

Singleton

In Kotlin, the object keyword is used to declare a singleton — a class with only one instance. It’s useful for utilities, managers, or storing global state.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Singleton object
object AppConfig {
    val appName = "Greedy Coder"
    var version = "1.0"

    fun printInfo() {
        println("App: $appName, Version: $version")
    }
}

// Main function
fun main() {
    // Access members directly without creating an instance
    AppConfig.printInfo()              // Output: App: Greedy Coder, Version: 1.0

    // Modify mutable properties
    AppConfig.version = "1.1"
    AppConfig.printInfo()              // Output: App: Greedy Coder, Version: 1.1
}

Data Object

A data object is a singleton (object) that also behaves like a data class, meaning it automatically generates toString(), equals(), and hashCode(). It’s ideal when need a single, constant instance with identity and equality.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Data object declaration
data object GuestUser {
    val name = "Guest"
    val role = "Viewer"
}

// Main function
fun main() {
    println(GuestUser)           // Output: GuestUser(name=Guest, role=Viewer)

    val user1 = GuestUser
    val user2 = GuestUser

    println(user1 == user2)      // Output: true (same instance)
    println(user1 === user2)     // Output: true (referential equality)
}

Enum Class

An enum class is used to define a fixed set of constants. It’s great for representing states, options, or categories like days of the week, directions, or user roles.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
enum class Direction {
    NORTH, SOUTH, EAST, WEST
}

enum class Planet(val gravity: Double) {
    EARTH(9.8),
    MARS(3.7),
    JUPITER(24.8)
}

fun main() {
    val dir = Direction.EAST
    println("Direction: $dir")         // Output: Direction: EAST

    val planet = Planet.MARS
    println("Planet: ${planet.name}")         // Output: Planet: MARS
    println("Gravity: ${planet.gravity} m/s²") // Output: Gravity: 3.7 m/s²
}

Sealed Class

A sealed class is used to define a closed set of subclasses. All possible subclasses must be declared in the same file, which helps Kotlin ensure exhaustive when expressions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Sealed class declaration
sealed class Operation {
  
    // Subclasses in the same file
    class Add(val a: Int, val b: Int) : Operation()
    class Subtract(val a: Int, val b: Int) : Operation()
    object NoOp : Operation()

}

fun perform(op: Operation): Int {
    return when (op) {
        is Add -> op.a + op.b
        is Subtract -> op.a - op.b
        NoOp -> 0
    }
}

// Main function
fun main() {
    val result1 = perform(Add(10, 5))        // Output: 15
    val result2 = perform(Subtract(10, 5))   // Output: 5
    val result3 = perform(NoOp)              // Output: 0

    println(result1)
    println(result2)
    println(result3)
}

Abstract class

An abstract class in Kotlin defines a base class that cannot be instantiated and may contain both abstract methods (without body) and concrete methods (with implementation). It’s used when you want to create a common structure for related classes while forcing them to implement specific behavior.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Abstract base class
abstract class Sensor(val name: String) {
    abstract fun readValue(): Double

    fun displayInfo() {
        println("Reading from $name sensor")
    }
}

// Subclass
class TemperatureSensor : Sensor("Temperature") {
    override fun readValue(): Double {
        return 36.5  // Simulated temperature value
    }
}

// Main function
fun main() {
    val tempSensor = TemperatureSensor()
    tempSensor.displayInfo()            // Output: Reading from Temperature sensor
    println("Value: ${tempSensor.readValue()} °C")  // Output: Value: 36.5 °C
}

Open Class

By default, all classes in Kotlin are final, meaning they can’t be inherited. To allow a class to be subclassed, you must mark it with the open keyword.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Base class marked as open
open class Vehicle {
    open fun start() {
        println("Vehicle is starting...")
    }
}

// Subclass
class Car : Vehicle() {
    override fun start() {
        println("Car is starting with key ignition.")
    }
}

// Main function
fun main() {
    val myCar = Car()
    myCar.start()   // Output: Car is starting with key ignition.
}

Anonymous Class

An anonymous class is an instance of a class created on-the-fly without explicitly declaring a subclass. It’s often used to implement interfaces or abstract classes quickly for one-time use. In Kotlin, you create anonymous classes using the object expression.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Abstract class
abstract class Sensor(val name: String) {
    abstract fun readValue(): Double
}

// Main function
fun main() {
    val lightSensor = object : Sensor("Light") {
        override fun readValue(): Double {
            return 120.0  // Simulated lux value
        }
    }

    println("Sensor: ${lightSensor.name}")             // Output: Sensor: Light
    println("Reading: ${lightSensor.readValue()} lx")  // Output: Reading: 120.0 lx
}

Value Class

A value class is a special kind of class introduced to provide type safety without runtime overhead. It wraps a single property but, at runtime, the compiler tries to avoid allocating an object, treating the value class like its underlying type (called inline class previously).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@JvmInline
value class Email(val value: String) {
    fun isValid(): Boolean {
        // Simple regex for email validation (basic example)
        return Regex("^[A-Za-z](.*)([@]{1})(.+)(\\.)(.+)").matches(value)
    }
}

fun sendWelcomeEmail(email: Email) {
    if (email.isValid()) {
        println("Sending welcome email to ${email.value}")
    } else {
        println("Invalid email: ${email.value}")
    }
}

fun main() {
    val email1 = Email("user@example.com")
    val email2 = Email("invalid-email")

    sendWelcomeEmail(email1)  // Output: Sending welcome email to user@example.com
    sendWelcomeEmail(email2)  // Output: Invalid email: invalid-email
}

Annotation Class

An annotation class is a special kind of class used to attach metadata to code elements (classes, functions, properties, etc.). Annotations can be used by the compiler, tools, or libraries for processing code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Define an annotation class
annotation class Info(val author: String, val version: Int)

// Use annotation on a class
@Info(author = "Tawhid", version = 1)
class MyClass {
    // ...
}

// Accessing annotation via reflection (optional)
fun main() {
    val annotations = MyClass::class.annotations
    for (annotation in annotations) {
        println(annotation)
    }
}

Inner class

An inner class is a nested class that holds a reference to an instance of its outer class. It can access members (including private ones) of the outer class. To declare an inner class in Kotlin, you use the inner keyword.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Sensor(val type: String) {
    private val id = 101

    inner class Calibration {
        fun showInfo() {
            println("Calibrating sensor type: $type with id: $id")
        }
    }
}

fun main() {
    val sensor = Sensor("Temperature")
    val calibration = sensor.Calibration()
    calibration.showInfo()  
    // Output: Calibrating sensor type: Temperature with id: 101
}

This post is licensed under CC BY 4.0 by the author.