Kotlin Class and Object

A Kotlin class is a blueprint or template that defines the structure and behavior of objects in your Android applications. Unlike Java, Kotlin class declaration is more concise and expressive. The Kotlin class keyword creates a reusable template that encapsulates data (properties) and functions (methods) together.

Kotlin class syntax follows this basic pattern:

class ClassName {  
    // Properties and functions  
}  

Every Kotlin class can contain properties, functions, constructors, and nested classes. Kotlin class definitions are fundamental to building robust Android applications with clean, maintainable code.

Basic Kotlin Class Declaration

Creating a Kotlin class is straightforward. Here’s how you declare a simple Kotlin class:

class Person {  
    var name: String = ""  
    var age: Int = 0  
      
    fun introduce() {  
        println("Hello, I'm $name and I'm $age years old")  
    }  
}  

This Kotlin class example demonstrates basic Kotlin class structure with properties (name, age) and a function (introduce). Kotlin class properties can be mutable (var) or immutable (val).

Kotlin Object Creation and Instantiation

Kotlin object creation doesn’t require the new keyword like Java. Kotlin object instantiation is clean and simple:

val person = Person()  
person.name = "John"  
person.age = 25  
person.introduce()  

Kotlin object instances are created by calling the class name like a function. This Kotlin object creation syntax is more intuitive than traditional object-oriented languages.

Kotlin Primary Constructor

Kotlin primary constructor is declared in the class header and provides a concise way to initialize Kotlin class properties. Kotlin constructor parameters can directly declare properties:

class Student(val name: String, var grade: Int, val studentId: String)  

This Kotlin primary constructor creates three properties automatically. The Kotlin constructor keyword can be omitted when there are no annotations or visibility modifiers.

Kotlin primary constructor with default values:

class Employee(val name: String, var salary: Double = 50000.0, val department: String = "General")  

Kotlin constructor default parameters allow flexible Kotlin object creation with optional arguments.

Kotlin Secondary Constructor

Kotlin secondary constructor provides additional ways to initialize Kotlin class instances. Kotlin secondary constructor uses the constructor keyword and must delegate to the Kotlin primary constructor:

class Vehicle(val brand: String, val model: String) {  
    var year: Int = 0  
      
    constructor(brand: String, model: String, year: Int) : this(brand, model) {  
        this.year = year  
    }  
      
    constructor(brand: String) : this(brand, "Unknown")  
}  

Kotlin secondary constructor enables multiple initialization paths while maintaining Kotlin class consistency.

Kotlin Init Block

Kotlin init block executes during Kotlin object initialization, after the Kotlin primary constructor. Kotlin init block is perfect for validation and setup logic:

class BankAccount(val accountNumber: String, initialBalance: Double) {  
    val balance: Double  
      
    init {  
        require(initialBalance >= 0) { "Initial balance cannot be negative" }  
        balance = initialBalance  
        println("Account $accountNumber created with balance $balance")  
    }  
}  

Kotlin init block runs every time a Kotlin object is created, ensuring proper initialization.

Kotlin Class Properties

Kotlin class properties can have custom getters and setters. Kotlin class property declaration supports both mutable and immutable properties:

class Rectangle(width: Double, height: Double) {  
    var width: Double = width  
        set(value) {  
            require(value > 0) { "Width must be positive" }  
            field = value  
        }  
      
    var height: Double = height  
        set(value) {  
            require(value > 0) { "Height must be positive" }  
            field = value  
        }  
      
    val area: Double  
        get() = width * height  
      
    val perimeter: Double  
        get() = 2 * (width + height)  
}  

Kotlin class properties with custom accessors provide encapsulation and validation.

Kotlin Companion Object

Kotlin companion object replaces static methods and properties from Java. Kotlin companion object belongs to the Kotlin class rather than instances:

class MathUtils {  
    companion object {  
        const val PI = 3.14159  
          
        fun calculateCircleArea(radius: Double): Double {  
            return PI * radius * radius  
        }  
          
        fun calculateCircleCircumference(radius: Double): Double {  
            return 2 * PI * radius  
        }  
    }  
}  

Kotlin companion object members are accessed using the class name:

val area = MathUtils.calculateCircleArea(5.0)  
val circumference = MathUtils.calculateCircleCircumference(5.0)  
println("PI value: ${MathUtils.PI}")  

Kotlin companion object can implement interfaces and extend classes, providing more flexibility than static members.

Kotlin Data Class

Kotlin data class automatically generates useful methods like toString(), equals(), hashCode(), and copy(). Kotlin data class is perfect for holding data:

data class User(val id: Int, val name: String, val email: String, var isActive: Boolean = true)  

Kotlin data class provides automatic method generation and destructuring capabilities:

val user = User(1, "Alice", "alice@example.com")  
val (id, name, email, isActive) = user  
val updatedUser = user.copy(isActive = false)  

Kotlin data class simplifies data management in Android applications.

Kotlin Object Declaration

Kotlin object declaration creates singleton instances. Kotlin object declaration ensures only one instance exists:

object DatabaseConfig {  
    const val DATABASE_NAME = "app_database"  
    const val DATABASE_VERSION = 1  
      
    fun getConnectionString(): String {  
        return "jdbc:sqlite:$DATABASE_NAME"  
    }  
}  

Kotlin object declaration is thread-safe and lazy by default.

Kotlin Nested and Inner Classes

Kotlin class can contain nested classes. Kotlin nested class doesn’t access outer class members by default:

class OuterClass(val outerProperty: String) {  
      
    class NestedClass {  
        fun nestedFunction() = "This is a nested class function"  
    }  
      
    inner class InnerClass {  
        fun innerFunction() = "Accessing outer property: $outerProperty"  
    }  
}  

Kotlin inner class (marked with inner) can access outer class members.

Kotlin Inheritance

Kotlin class inheritance uses the : symbol. Kotlin class must be marked open to allow inheritance:

open class Animal(val name: String) {  
    open fun makeSound() {  
        println("$name makes a sound")  
    }  
}  
  
class Dog(name: String, val breed: String) : Animal(name) {  
    override fun makeSound() {  
        println("$name barks")  
    }  
      
    fun wagTail() {  
        println("$name wags tail")  
    }  
}  

Kotlin class inheritance enables code reuse and polymorphism.

Kotlin Abstract Class

Kotlin abstract class cannot be instantiated directly. Kotlin abstract class can contain abstract and concrete members:

abstract class Shape {  
    abstract val area: Double  
    abstract fun draw()  
      
    fun displayInfo() {  
        println("This shape has area: $area")  
    }  
}  
  
class Circle(val radius: Double) : Shape() {  
    override val area: Double  
        get() = 3.14159 * radius * radius  
      
    override fun draw() {  
        println("Drawing a circle with radius $radius")  
    }  
}  

Kotlin abstract class provides a base for related classes.

Kotlin Class Visibility Modifiers

Kotlin class supports visibility modifiers: public (default), private, protected, and internal:

class AccessModifierDemo {  
    public val publicProperty = "Everyone can access"  
    private val privateProperty = "Only this class can access"  
    protected val protectedProperty = "This class and subclasses can access"  
    internal val internalProperty = "Same module can access"  
      
    private fun privateFunction() = "Private function"  
      
    protected fun protectedFunction() = "Protected function"  
      
    internal fun internalFunction() = "Internal function"  
}  

Kotlin class visibility modifiers control access to class members.

Complete Kotlin Class and Object Example

Here’s a comprehensive example demonstrating Kotlin class, Kotlin object, Kotlin constructor, and Kotlin companion object concepts:

// Import statements  
import kotlin.random.Random  
  
// Data class for holding customer information  
data class CustomerInfo(  
    val customerId: String,  
    val name: String,  
    val email: String,  
    var loyaltyPoints: Int = 0  
)  
  
// Main shopping cart class  
class ShoppingCart(private val customerId: String) {  
    // Properties  
    private val items = mutableListOf<CartItem>()  
    private var discount: Double = 0.0  
      
    // Secondary constructor  
    constructor(customerId: String, initialDiscount: Double) : this(customerId) {  
        this.discount = initialDiscount  
    }  
      
    // Init block for validation  
    init {  
        require(customerId.isNotBlank()) { "Customer ID cannot be blank" }  
        println("Shopping cart created for customer: $customerId")  
    }  
      
    // Properties with custom getters  
    val itemCount: Int  
        get() = items.size  
      
    val totalAmount: Double  
        get() = items.sumOf { it.totalPrice } * (1 - discount)  
      
    // Methods  
    fun addItem(product: String, price: Double, quantity: Int = 1) {  
        val item = CartItem(product, price, quantity)  
        items.add(item)  
        println("Added ${item.product} to cart")  
    }  
      
    fun removeItem(product: String) {  
        items.removeIf { it.product == product }  
        println("Removed $product from cart")  
    }  
      
    fun applyDiscount(discountPercent: Double) {  
        require(discountPercent in 0.0..100.0) { "Discount must be between 0 and 100 percent" }  
        this.discount = discountPercent / 100.0  
    }  
      
    fun checkout(): OrderSummary {  
        val orderId = OrderIdGenerator.generateOrderId()  
        val summary = OrderSummary(orderId, customerId, items.toList(), totalAmount)  
        items.clear()  
        return summary  
    }  
      
    // Companion object for static-like functionality  
    companion object {  
        const val MAX_ITEMS = 50  
        private var totalCartsCreated = 0  
          
        fun getCartStatistics(): String {  
            return "Total shopping carts created: $totalCartsCreated"  
        }  
          
        init {  
            println("ShoppingCart companion object initialized")  
        }  
    }  
      
    // Inner class for cart items  
    inner class CartItem(  
        val product: String,  
        val price: Double,  
        val quantity: Int  
    ) {  
        val totalPrice: Double = price * quantity  
          
        fun getCartReference(): ShoppingCart = this@ShoppingCart  
    }  
      
    // Nested class for order summary  
    class OrderSummary(  
        val orderId: String,  
        val customerId: String,  
        val items: List<CartItem>,  
        val totalAmount: Double  
    ) {  
        fun printSummary() {  
            println("=== ORDER SUMMARY ===")  
            println("Order ID: $orderId")  
            println("Customer ID: $customerId")  
            println("Items: ${items.size}")  
            println("Total Amount: $${String.format("%.2f", totalAmount)}")  
        }  
    }  
}  
  
// Object declaration for singleton functionality  
object OrderIdGenerator {  
    private var currentId = 1000  
      
    fun generateOrderId(): String {  
        return "ORD-${++currentId}-${Random.nextInt(1000, 9999)}"  
    }  
      
    fun getNextIdPreview(): String {  
        return "ORD-${currentId + 1}-XXXX"  
    }  
}  
  
// Abstract class for different customer types  
abstract class Customer(val customerId: String, val name: String) {  
    abstract fun calculateDiscount(): Double  
      
    fun displayCustomerInfo() {  
        println("Customer: $name (ID: $customerId)")  
        println("Discount Rate: ${calculateDiscount()}%")  
    }  
}  
  
// Concrete customer classes  
class RegularCustomer(customerId: String, name: String) : Customer(customerId, name) {  
    override fun calculateDiscount(): Double = 5.0  
}  
  
class PremiumCustomer(customerId: String, name: String, private val loyaltyYears: Int) : Customer(customerId, name) {  
    override fun calculateDiscount(): Double = 5.0 + (loyaltyYears * 2.0)  
}  
  
// Extension function for ShoppingCart  
fun ShoppingCart.addMultipleItems(vararg items: Pair<String, Double>) {  
    items.forEach { (product, price) ->  
        addItem(product, price)  
    }  
}  
  
// Main function demonstrating usage  
fun main() {  
    // Create customer info using data class  
    val customerInfo = CustomerInfo("CUST-001", "John Doe", "john@example.com", 150)  
    println("Customer: ${customerInfo.name}")  
      
    // Create shopping cart using primary constructor  
    val cart = ShoppingCart(customerInfo.customerId)  
      
    // Add items to cart  
    cart.addItem("Laptop", 999.99)  
    cart.addItem("Mouse", 29.99, 2)  
    cart.addItem("Keyboard", 79.99)  
      
    // Use extension function  
    cart.addMultipleItems(  
        "Monitor" to 299.99,  
        "Webcam" to 89.99  
    )  
      
    // Apply discount  
    cart.applyDiscount(10.0)  
      
    // Display cart information  
    println("Items in cart: ${cart.itemCount}")  
    println("Total amount: $${String.format("%.2f", cart.totalAmount)}")  
      
    // Checkout  
    val orderSummary = cart.checkout()  
    orderSummary.printSummary()  
      
    // Use singleton object  
    println("Next order ID will be: ${OrderIdGenerator.getNextIdPreview()}")  
      
    // Use companion object  
    println(ShoppingCart.getCartStatistics())  
      
    // Create different customer types  
    val regularCustomer = RegularCustomer("CUST-002", "Jane Smith")  
    val premiumCustomer = PremiumCustomer("CUST-003", "Bob Johnson", 3)  
      
    regularCustomer.displayCustomerInfo()  
    premiumCustomer.displayCustomerInfo()  
      
    // Create another cart with secondary constructor  
    val discountedCart = ShoppingCart("CUST-004", 0.15)  
    discountedCart.addItem("Book", 19.99)  
    println("Discounted cart total: $${String.format("%.2f", discountedCart.totalAmount)}")  
}  

Output

When you run this comprehensive Kotlin class and object example, you’ll see:

ShoppingCart companion object initialized  
Customer: John Doe  
Shopping cart created for customer: CUST-001  
Added Laptop to cart  
Added Mouse to cart  
Added Keyboard to cart  
Added Monitor to cart  
Added Webcam to cart  
Items in cart: 5  
Total amount: $1349.95  
=== ORDER SUMMARY ===  
Order ID: ORD-1001-7823  
Customer ID: CUST-001  
Items: 5  
Total Amount: $1349.95  
Next order ID will be: ORD-1002-XXXX  
Total shopping carts created: 0  
Customer: Jane Smith (ID: CUST-002)  
Discount Rate: 5.0%  
Customer: Bob Johnson (ID: CUST-003)  
Discount Rate: 11.0%  
Shopping cart created for customer: CUST-004  
Added Book to cart  
Discounted cart total: $16.99  

This comprehensive Kotlin class and object tutorial covers all essential concepts including Kotlin constructor, Kotlin companion object, Kotlin data class, inheritance, and practical usage patterns. Understanding these Kotlin class concepts is crucial for effective Android development and modern Kotlin programming.