Kotlin Constructors

Kotlin constructors are special member functions that initialize class instances when objects are created. Unlike Java, Kotlin provides two distinct types of constructors: primary constructors and secondary constructors. The primary constructor is declared in the class header, while secondary constructors are defined within the class body using the constructor keyword.

Every Kotlin class can have one primary constructor and multiple secondary constructors. The primary constructor cannot contain executable code, but you can use init blocks to execute initialization logic. This design makes Kotlin constructors more structured and predictable than their Java counterparts.

Kotlin Primary Constructor

The Kotlin primary constructor is the most concise way to initialize class properties. It’s declared immediately after the class name and becomes part of the class header. Here’s the basic syntax for a primary constructor:

class ClassName constructor(parameter1: Type, parameter2: Type) {
    // class body
}

You can omit the constructor keyword when there are no annotations or visibility modifiers:

class Person(val name: String, var age: Int) {
    // class body
}

Primary Constructor Properties

When you declare parameters in a primary constructor, you can simultaneously declare class properties by using val or var keywords:

  • val creates a read-only property (immutable)
  • var creates a mutable property
class Student(val studentId: String, var grade: Double) {
    // studentId is read-only, grade is mutable
}

Primary Constructor with Default Parameters

Kotlin constructors support default parameters, eliminating the need for multiple constructor overloads:

class GameCharacter(
    val name: String = "Anonymous", 
    var level: Int = 1, 
    var health: Double = 100.0
) {
    // Properties with default values
}

This allows flexible object creation:

val character1 = GameCharacter()                          // Uses all defaults
val character2 = GameCharacter("Warrior")                 // Custom name, default level and health
val character3 = GameCharacter("Mage", 5)                // Custom name and level
val character4 = GameCharacter("Archer", 3, 85.5)       // All custom values

Kotlin Init Blocks

Since primary constructors cannot contain executable code, Kotlin provides init blocks for initialization logic. Init blocks are executed when the class instance is created and have access to primary constructor parameters:

class Vehicle(val brand: String, val model: String) {
    val vehicleInfo: String
    
    init {
        println("Creating vehicle: $brand $model")
        vehicleInfo = "$brand $model".uppercase()
        
        // Validation logic
        require(brand.isNotEmpty()) { "Brand cannot be empty" }
        require(model.isNotEmpty()) { "Model cannot be empty" }
    }
}

Multiple Init Blocks

A class can have multiple init blocks, and they execute in the order they appear:

class DatabaseConnection(val host: String, val port: Int) {
    val connectionString: String
    var isConnected: Boolean = false
    
    init {
        println("Initializing database connection...")
        connectionString = "jdbc:postgresql://$host:$port/database"
    }
    
    init {
        println("Validating connection parameters...")
        require(port in 1..65535) { "Invalid port number: $port" }
    }
    
    init {
        println("Establishing connection...")
        isConnected = true
        println("Connection established successfully!")
    }
}

Kotlin Secondary Constructors

Secondary constructors provide alternative ways to initialize objects when the primary constructor isn’t sufficient. They’re declared using the constructor keyword and must delegate to the primary constructor using the this keyword:

class Rectangle(val width: Double, val height: Double) {
    val area: Double = width * height
    
    // Secondary constructor for square
    constructor(side: Double) : this(side, side) {
        println("Creating square with side: $side")
    }
    
    // Secondary constructor with default dimensions
    constructor() : this(1.0, 1.0) {
        println("Creating unit rectangle")
    }
}

Secondary Constructor Delegation Rules

Every secondary constructor must directly or indirectly delegate to the primary constructor:

class BankAccount(val accountNumber: String, var balance: Double) {
    val accountType: String
    
    init {
        accountType = if (balance >= 10000) "Premium" else "Standard"
        println("Account created: $accountNumber, Type: $accountType")
    }
    
    // Secondary constructor with default balance
    constructor(accountNumber: String) : this(accountNumber, 0.0) {
        println("Account opened with zero balance")
    }
    
    // Secondary constructor delegating to another secondary constructor
    constructor() : this("AUTO-${System.currentTimeMillis()}") {
        println("Auto-generated account number")
    }
}

Advanced Kotlin Constructor Features

Constructor Visibility Modifiers

You can control constructor visibility using access modifiers:

class SecureData private constructor(val data: String) {
    companion object {
        fun createSecureData(input: String): SecureData? {
            return if (input.length >= 8) {
                SecureData(input.reversed())
            } else {
                null
            }
        }
    }
}

Constructor with Annotations

When using annotations or visibility modifiers, the constructor keyword becomes mandatory:

class ApiClient @Inject constructor(
    private val httpClient: HttpClient,
    private val apiKey: String
) {
    // class implementation
}

Property Initialization in Constructor Body

You can initialize properties that aren’t declared in the primary constructor:

class MusicPlayer(val brand: String) {
    val supportedFormats: List<String>
    var volume: Int
    var isPlaying: Boolean
    
    init {
        supportedFormats = listOf("MP3", "FLAC", "WAV", "AAC")
        volume = 50
        isPlaying = false
        println("$brand music player initialized")
    }
}

Full Example: E-commerce Product Class

Here’s a comprehensive example demonstrating all Kotlin constructor concepts:

// Import statements (if needed)
import java.time.LocalDateTime
import java.util.*

class Product(
    val id: String,
    val name: String,
    var price: Double,
    val category: String = "General"
) {
    val productCode: String
    var stock: Int = 0
    var isAvailable: Boolean = false
    val createdAt: LocalDateTime
    val tags: MutableList<String> = mutableListOf()
    
    init {
        // Generate product code
        productCode = "${category.uppercase()}-${id}"
        createdAt = LocalDateTime.now()
        
        // Validate price
        require(price >= 0) { "Price cannot be negative: $price" }
        require(name.isNotBlank()) { "Product name cannot be blank" }
        
        println("Product created: $productCode - $name")
    }
    
    init {
        // Set default availability based on category
        isAvailable = category != "Restricted"
        println("Product availability set to: $isAvailable")
    }
    
    // Secondary constructor for discounted products
    constructor(
        id: String, 
        name: String, 
        originalPrice: Double, 
        discountPercent: Double, 
        category: String
    ) : this(id, name, originalPrice * (1 - discountPercent / 100), category) {
        tags.add("Discounted")
        println("Discounted product created with ${discountPercent}% off")
    }
    
    // Secondary constructor for limited edition products
    constructor(
        id: String, 
        name: String, 
        price: Double, 
        category: String, 
        limitedStock: Int
    ) : this(id, name, price, category) {
        stock = limitedStock
        tags.addAll(listOf("Limited Edition", "Exclusive"))
        println("Limited edition product created with stock: $limitedStock")
    }
    
    // Method to display product information
    fun displayInfo() {
        println("""
            Product Information:
            Code: $productCode
            Name: $name
            Price: $${String.format("%.2f", price)}
            Category: $category
            Stock: $stock
            Available: $isAvailable
            Tags: ${tags.joinToString(", ")}
            Created: $createdAt
        """.trimIndent())
    }
    
    // Method to update stock
    fun updateStock(newStock: Int) {
        require(newStock >= 0) { "Stock cannot be negative" }
        stock = newStock
        isAvailable = stock > 0
        println("Stock updated to: $stock, Available: $isAvailable")
    }
    
    // Method to add tags
    fun addTag(tag: String) {
        if (!tags.contains(tag)) {
            tags.add(tag)
            println("Tag added: $tag")
        }
    }
}

// Demonstration function
fun main() {
    println("=== Kotlin Constructors Demo ===\n")
    
    // Using primary constructor with default parameter
    val laptop = Product("LAP001", "Gaming Laptop", 1299.99)
    laptop.updateStock(15)
    laptop.addTag("Gaming")
    laptop.displayInfo()
    
    println("\n" + "=".repeat(50) + "\n")
    
    // Using secondary constructor for discounted product
    val smartphone = Product("PHN001", "Flagship Phone", 999.99, 15.0, "Electronics")
    smartphone.updateStock(25)
    smartphone.displayInfo()
    
    println("\n" + "=".repeat(50) + "\n")
    
    // Using secondary constructor for limited edition
    val collectible = Product("COL001", "Vintage Watch", 2499.99, "Luxury", 5)
    collectible.displayInfo()
    
    println("\n" + "=".repeat(50) + "\n")
    
    // Creating products with different parameter combinations
    val basicProduct = Product("BAS001", "Office Chair", 199.99, "Furniture")
    basicProduct.updateStock(50)
    
    val premiumProduct = Product("PRE001", "Executive Desk", 899.99, "Premium")
    premiumProduct.updateStock(10)
    premiumProduct.addTag("Premium Quality")
    
    println("Basic Product: ${basicProduct.name} - ${basicProduct.productCode}")
    println("Premium Product: ${premiumProduct.name} - ${premiumProduct.productCode}")
}

Expected Output:

=== Kotlin Constructors Demo ===

Product created: GENERAL-LAP001 - Gaming Laptop
Product availability set to: true
Stock updated to: 15, Available: true
Tag added: Gaming
Product Information:
Code: GENERAL-LAP001
Name: Gaming Laptop
Price: $1299.99
Category: General
Stock: 15
Available: true
Tags: Gaming
Created: 2025-06-20T10:30:45.123

==================================================

Product created: ELECTRONICS-PHN001 - Flagship Phone
Product availability set to: true
Discounted product created with 15.0% off
Stock updated to: 25, Available: true
Product Information:
Code: ELECTRONICS-PHN001
Name: Flagship Phone
Price: $849.99
Category: Electronics
Stock: 25
Available: true
Tags: Discounted
Created: 2025-06-20T10:30:45.156

==================================================

Product created: LUXURY-COL001 - Vintage Watch
Product availability set to: true
Limited edition product created with stock: 5
Product Information:
Code: LUXURY-COL001
Name: Vintage Watch
Price: $2499.99
Category: Luxury
Stock: 5
Available: true
Tags: Limited Edition, Exclusive
Created: 2025-06-20T10:30:45.189

==================================================

Product created: FURNITURE-BAS001 - Office Chair
Product availability set to: true
Stock updated to: 50, Available: true
Product created: PREMIUM-PRE001 - Executive Desk
Product availability set to: true
Stock updated to: 10, Available: true
Tag added: Premium Quality
Basic Product: Office Chair - FURNITURE-BAS001
Premium Product: Executive Desk - PREMIUM-PRE001