What a constructor does
A constructor runs when you create an object and sets up its initial state. Without one, you would create an empty Dog and then fill in its name and age line by line, which is noisy and easy to forget. With a constructor, the call Dog("Rex", 4) produces a dog that is ready to use.
The primary constructor
Kotlin's usual way is the primary constructor, written in the class header right after the name:
class Dog(var name: String, var age: Int)
Putting var or val before a parameter does two jobs in one: it takes the argument and it declares a property of the same name, initialized with that argument. This single line replaces a class with two property declarations plus a constructor that assigns them. Use var for a property that may change later and val for one that must not. A class with no body needs no braces.
Create objects by passing the arguments:
val rex = Dog("Rex", 4)
val luna = Dog("Luna", 7)
By the time each line finishes, rex.name is "Rex" and rex.age is 4, and the same holds for Luna.
Parameters without val or var
A primary constructor parameter without val or var is only an argument. It is available while the object is built, in property initializers and init blocks, but it does not become a property and methods cannot see it. This matters for inheritance later, and it is a common slip: in class Dog(name: String), a method that reads name fails with unresolved reference 'name'.
Secondary constructors and init blocks
A class can also declare constructors with the constructor keyword inside its body. They have no return type, not even Unit. This form needs the properties declared separately, and it uses this to tell the property from the parameter that shares its name:
class Bird {
var name: String
var age: Int
constructor(name: String, age: Int) {
this.name = name
this.age = age
}
constructor(name: String) : this(name, 1)
}
Inside the constructor, a bare name is the parameter, because the local name wins. this is the current object, so this.name is the property. The second constructor delegates with : this(name, 1), which calls the first one and fills in a default age. With a primary constructor present, every secondary constructor must delegate to it this way.
When the primary constructor needs more than assignments, put the extra code in an init block. It runs as part of construction, after the properties declared above it are set:
class Cat(val name: String, age: Int) {
val label: String
init {
label = "$name ($age)"
}
}
Often you do not need a secondary constructor at all. Default values give the same effect: class Fish(val name: String, val age: Int = 0) lets you write Fish("Nemo"), and named arguments let you write Fish(age = 2, name = "Dory").
The default constructor
A class with no constructor declared gets a hidden one with no parameters. That is why Dog() worked in earlier lessons. As soon as you declare a constructor with parameters, that free one is gone. After class Dog(var name: String, var age: Int), the call Dog() fails with no value passed for parameter 'name' and another error for age. Give the parameters default values, or add a no-argument secondary constructor, if you still want Dog() to work.
The exercise
The starter code prints rex.name, rex.age and the same for luna but defines neither the class nor the variables. There are two steps. First, declare Dog with a primary constructor whose name: String and age: Int are var parameters. Second, create the dogs in mainFunction:
class Dog(var name: String, var age: Int)
class Solution {
fun mainFunction() {
val rex = Dog("Rex", 4)
val luna = Dog("Luna", 7)
println(rex.name + " is " + rex.age)
println(luna.name + " is " + luna.age)
}
}
It prints:
Rex is 4
Luna is 7
The + between a String and an Int works because the left side is a string; Kotlin converts the number to text.
Common mistakes
- Forgetting
varorval.class Dog(name: String, age: Int)compiles, butrex.namethen fails, since no property exists. - Swapped arguments.
Dog(4, "Rex")does not compile, because the types are checked against the parameter order. - Calling
Dog()after adding parameters. The no-argument constructor no longer exists unless you provide it. - Writing
new. Constructors are called like functions:Dog("Rex", 4).
Key takeaways
- The primary constructor lives in the class header;
valorvaron a parameter creates a property. - Secondary constructors use the
constructorkeyword and must delegate to the primary one withthis(...). - Use
this.nameto reach a property that a parameter shadows. - Declaring any constructor with parameters removes the free no-argument constructor.
- Default parameter values often replace the need for several constructors.