Kotlin Constructors
A constructor is a special function that runs when you create a new object from a class. It sets up the initial state of the object. Kotlin supports a primary constructor and one or more secondary constructors.
Primary Constructor
The primary constructor is declared directly in the class header. It is the most common and concise way to create objects:
class Student(val name: String, val grade: Int, val school: String)
fun main() {
val s = Student("Riya", 10, "Greenwood High")
println("${s.name} is in grade ${s.grade} at ${s.school}")
}val vs var in Constructor
class Employee(
val name: String, // read-only property
var salary: Int // changeable property
)
val emp = Employee("Leon", 60000)
// emp.name = "Leo" ← ERROR: val cannot be changed
emp.salary = 65000 // OK: var can be updatedConstructor Parameters Without Properties
Sometimes you only need a parameter to compute something during setup, not store it permanently:
class Circle(radius: Double) { // no val/var — not a property
val area: Double = Math.PI * radius * radius
val circumference: Double = 2 * Math.PI * radius
}
val c = Circle(5.0)
println("Area: ${"%.2f".format(c.area)}") // 78.54
println("Circumference: ${"%.2f".format(c.circumference)}") // 31.42
// c.radius ← ERROR: radius is not a property hereinit Block with Primary Constructor
class Product(val name: String, val price: Double) {
init {
require(price > 0) { "Price must be positive, got $price" }
println("Product created: $name at ₹$price")
}
}
val p1 = Product("Pen", 10.0) // OK
// val p2 = Product("Eraser", -5.0) // throws IllegalArgumentExceptionSecondary Constructor
A secondary constructor provides an alternative way to create objects with different parameters. It must call the primary constructor using this():
class Box(val length: Int, val width: Int, val height: Int) {
val volume = length * width * height
// Secondary: create a cube (all sides equal)
constructor(side: Int) : this(side, side, side)
// Secondary: create a flat box (height = 1)
constructor(length: Int, width: Int) : this(length, width, 1)
}
fun main() {
val box1 = Box(4, 3, 2) // primary constructor
val cube = Box(5) // secondary: 5×5×5
val flat = Box(6, 4) // secondary: 6×4×1
println("Box1 volume: ${box1.volume}") // 24
println("Cube volume: ${cube.volume}") // 125
println("Flat volume: ${flat.volume}") // 24
}Default Values as Constructor Alternative
In most cases, you can avoid secondary constructors entirely by using default values in the primary constructor:
class Config(
val host: String = "localhost",
val port: Int = 8080,
val debug: Boolean = false
)
val c1 = Config() // all defaults
val c2 = Config("api.example.com", 443) // custom host and port
val c3 = Config(debug = true) // only debug changedConstructor Flow Diagram
User calls: Student("Priya", 10, "Greenwood High")
│
▼
Primary constructor runs:
name = "Priya"
grade = 10
school = "Greenwood High"
│
▼
init block runs (if any):
println("Welcome, Priya!")
│
▼
Object is ready to use
Practical Example: User Registration
class User(
val username: String,
val email: String,
val role: String = "member"
) {
val userId: String = username.lowercase().replace(" ", "_")
init {
require(email.contains("@")) { "Invalid email: $email" }
println("User registered: $username ($role)")
}
fun profile() = "[$userId] $username | $email | Role: $role"
}
fun main() {
val u1 = User("Alice Smith", "alice@mail.com")
val u2 = User("Bob Ray", "bob@corp.com", "admin")
println(u1.profile())
println(u2.profile())
}Output:
User registered: Alice Smith (member)
User registered: Bob Ray (admin)
[alice_smith] Alice Smith | alice@mail.com | Role: member
[bob_ray] Bob Ray | bob@corp.com | Role: admin