Constructor
A constructor is a special function or code block that is used to initialize an instance of a class. It is invoked when an object of the class is created. It defines how an object of a class is created and sets up its initial state.
There are two types of constructors in Kotlin:
1. Primary Constructor:
2. Secondary Constructor:
1. Primary Constructor:
- The primary constructor is defined in the class header itself, right after the class name.
- It can have properties (parameters) that are used to initialize the class.
- It is used to set up the initial state of the class.
Here’s the syntax for the primary constructor:
class MyClass(parameter1: Type1, parameter2: Type2, ...) {
// Class body
}
In this syntax:
MyClass
is the name of the class.parameter1
,parameter2
, etc., are the parameters of the constructor.Type1
,Type2
, etc., are the types of the parameters.
Kotlin program of primary constructor:
class Person(val firstName: String, val lastName: String, val age: Int) {
fun personDetails(): String {
return "Name: $firstName $lastName\nAge: $age"
}
}
fun main() {
val person = Person("John", "Doe", 25)
val details = person.personDetails()
println(details)
}
/**
Output
Name: John Doe
Age: 25
**/
Here, Person
is the class, and it has a primary constructor , firstName, lastName, and age are parameters of the primary constructor, they are declared as properties of the class.
Note: If you don’t declare any visibility modifier (like public
, private
, etc.) for the constructor, it is public
by default.
Kotlin program of primary constructor with initializer block
class Person(firstName: String, lastName: String, age: Int) {
// Properties defined in the primary constructor.
val fullName: String
init {
// Code inside init block is executed when an instance is created.
fullName = "$firstName $lastName"
println("init executed ")
}
}
fun main(){
val p1 = Person(firstName = "Green", lastName = "Bruce",23)
print(p1.fullName)
}
Output:
init executed
Green Bruce
In this example, Person class has a primary constructor that takes firstName, lastName, and age as parameters. The init block is used to execute code during instance initialization.
2. Secondary Constructor:
- A class can have one or more secondary constructors.
- They are defined using the constructor keyword.
- Secondary constructors must call the primary constructor or another secondary constructor using the this keyword.
Secondary constructors can be defined in a class using the constructor keyword. Secondary constructors allow you to provide additional ways to initialize your class. Here’s the syntax for a secondary constructor:
class MyClass {
// Primary constructor and class body
// Secondary constructor
constructor(parameter1: Type1, parameter2: Type2, ...) {
// Initialization code
}
// Additional methods, properties, etc.
}
In this syntax:
class MyClass
is the class declaration.- The primary constructor, if any, is declared within the class header.
- The secondary constructor is declared using the
constructor
keyword followed by its parameters. - Inside the secondary constructor’s body, you can write the code necessary to initialize the class or perform additional logic.
Kotlin Program Of Secondary Constructor
class Person {
var name: String = ""
var age: Int = 0
constructor(name: String, age: Int) {
this.name = name
this.age = age
}
}
fun main() {
val person1 = Person("John", 25)
println("Name: ${person1.name}, Age: ${person1.age}")
}
/**
Output
Name: John, Age: 25
*/
In above example secondary constructor is defined that takes two parameters (name
and age
). Inside the secondary constructor, the properties name
and age
are initialized with the values passed as parameters using this.
Kotlin Program Of multiple secondary constructors
class Person {
var firstName: String = ""
var lastName: String = ""
var age: Int = 0
// First constructor
constructor(firstName: String, lastName: String, age: Int) {
this.firstName = firstName
this.lastName = lastName
this.age = age
println("First constructor called")
}
// Secondary constructor without age parameter
constructor(firstName: String, lastName: String) : this(firstName, lastName, 0) {
println("Secondary constructor without age parameter called")
}
// Secondary constructor without any parameters
constructor() : this("Unknown", "Unknown", 0) {
println("Secondary constructor without any parameters called")
}
// Method
fun displayDetails() {
println("Name: $firstName $lastName, Age: $age")
}
}
fun main() {
// Using the primary constructor
val person1 = Person("John", "Doe", 25)
person1.displayDetails()
println()
// Using the secondary constructor without age parameter
val person2 = Person("Jane", "Smith")
person2.displayDetails()
println()
// Using the secondary constructor without any parameters
val person3 = Person()
person3.displayDetails()
println()
}
In this example:
- The class
Person
has a primary constructor and two secondary constructors. - The constructor(firstName: String, lastName: String, age: Int) initializes the
firstName
,lastName
, andage
properties using this. - The constructor(firstName: String, lastName: String) is the cases where the age is provided by this(..), this(..) syntax will call first secondary constructor.
- The constructor(firstName: String, lastName: String) is for cases where only the name is provided, and it calls the first constructor by providing a default value for age using this(..).
- The third secondary constructor constructor() is for where no parameters are provided, and this(..) delegates to the second constructor by providing default values for name and age.
When you run the main
function, you’ll see that each constructor is called based on how the Person
instances are created.
Output
First constructor called
Name: John Doe, Age: 25
First constructor called
Secondary constructor without age parameter called
Name: Jane Smith, Age: 0
First constructor called
Secondary constructor without any parameters called
Name: Unknown Unknown, Age: 0
Execution Order Of Static Initializer, Primary Constructor, init Blocks:
class MyClass {
companion object {
init {
println("Static Initializer")
}
}
init {
println("Init Block 1")
}
val property1: String
constructor(param: String) {
println("Constructor")
property1 = param
}
init {
println("Init Block 2")
}
}
fun main() {
val instance = MyClass("Hello")
}
//Output
Static Initializer
Init Block 1
Init Block 2
Constructor
In this example, you can see the order of execution for the static initializer, init
blocks, and the constructor. Keep in mind that the static initializer is executed only once when the class is loaded, while the init
blocks and primary constructor are executed each time an instance is created.
Note: if In the class , primary constructor is deined with no properties, and define the secondary constructor. primary constructor must be called using this() with their params otherwise will get an error(Primary constructor call expected)
class Person() {
var fullName: String? = null
constructor(fName: String) : this() {
this.fullName = fName
println("no parameter constructor run ")
println("$fullName")
}
}
Note: In below example, the primary constructor is implicitly called before the body of the secondary constructor. So, when an instance of Person
is created using the secondary constructor, the primary constructor is automatically invoked.
class Person {
var fullName: String? = null
constructor(fName: String){
this.fullName = fName
println("no parameter constructor run ")
println("$fullName")
}
}
In above case primary constructor is responsible for initializing properties. the fullName
property is initialized directly in the primary constructor with a default value of null
. Therefore, when you create an instance using the secondary constructor, the fullName
property is already initialized.
Kotlin program of calling one constructor from another ?
One constructor can be called from another using the this keyword. This is done in the secondary constructor to ensure that the object is properly initialized.
1. Example of Secondary constructor that calls the primary constructor
class Person(val name: String, val age: Int) {
init {
println("Primary constructor: Name: $name, Age: $age")
}
// Secondary constructor calling the primary constructor
constructor(name: String) : this(name, 0) {
println("Secondary constructor: Default age (0) assigned.")
}
}
fun main() {
// Creating an instance using the primary constructor
val person1 = Person("John", 30)
// Creating an instance using the secondary constructor
val person2 = Person("Jane")
// Output:
// Primary constructor: Name: John, Age: 30
// Secondary constructor: Default age (0) assigned.
}
In this example The class also has a secondary constructor that takes a single parameter name
. This secondary constructor calls the primary constructor using this(name, 0)
, providing a default value of 0
for the age
parameter.
2. Example of one secondary constructor calls another secondary constructor :
Here’s an example of a Kotlin class with two secondary constructors, where one secondary constructor calls another:
class Person {
var fullName: String = ""
var age: Int = 0
// Secondary constructor #1
constructor(firstName: String, lastName: String) {
fullName = "$firstName $lastName"
}
// Secondary constructor #2 - calls the first constructor
constructor(firstName: String, lastName: String, age: Int) : this(firstName, lastName) {
this.age = age
fullName = "$fullName ($age years old)"
}
}
In this example, we have a Person class with two secondary constructors:
- Secondary Constructor #1:
- Takes firstName and lastName as parameters.
- Initializes the fullName property by concatenating the first and last names.
- Secondary Constructor #2:
- Takes firstName, lastName, and age as parameters.
- Calls the first secondary constructor using this(firstName, lastName).
- Initializes the age property and updates the fullName to include the age.
Example of creating Person objects:
class Person {
var fullName: String = ""
var age: Int = 0
// Secondary constructor #1
constructor(firstName: String, lastName: String) {
fullName = "$firstName $lastName"
}
// Secondary constructor #2 - calls the first constructor
constructor(firstName: String, lastName: String, age: Int) : this(firstName, lastName) {
this.age = age
fullName = "$fullName ($age years old)"
}
}
fun main() {
val person1 = Person("Alice", "Smith")
println("Full Name: ${person1.fullName}, Age: ${person1.age}") // Output: Full Name: Alice Smith, Age: 0
val person2 = Person("Bob", "Johnson", 25)
println("Full Name: ${person2.fullName}, Age: ${person2.age}") // Output: Full Name: Bob Johnson (25 years old), Age: 25
}
Output
Output
Full Name: Alice Smith, Age: 0
Full Name: Bob Johnson (25 years old), Age: 25
Example of Calling constructor of parent class from child class
you can call a constructor of the parent class from the child class by using the super keyword.
1. Example of calling primary constructor of parent from child class
open class Parent(val name: String) {
init {
println("Initializing Parent with name: $name")
}
}
class Child(name: String, val age: Int) : Parent(name) {
init {
println("Initializing Child with age: $age")
}
}
In this Example, The Child class extends Parent and takes name and age as parameters in its primary constructor. The : Parent(name) syntax indicates that the Parent constructor with the name parameter should be called.
When you create an instance of Child, both the Parent and Child initializers will be called:
fun main() {
val child = Child("Alice", 30)
// Output:
// Initializing Parent with name: Alice
// Initializing Child with age: 30
}
when a Child object is created, the Parent class’s constructor is called first (via super(name)), followed by the Child class’s constructor.
2. Calling parent class secondary constructor from child class secondary constructor
when you need to call a secondary constructor of the parent class from a secondary constructor of the child class, you use the super keyword with the appropriate arguments.
open class Parent {
var firstName: String = ""
var lastName: String = ""
constructor(firstName: String, lastName: String) {
this.firstName = firstName
this.lastName = lastName
println("Parent Secondary Constructor Called")
}
}
class Child : Parent {
var age: Int = 0
constructor(firstName: String, lastName: String, age: Int) : super(firstName, lastName) {
this.age = age
println("Child Secondary Constructor Called")
}
}
fun main() {
val child = Child("Alice", "Smith", 30)
println("Name: ${child.firstName} ${child.lastName}, Age: ${child.age}")
}
Inside the Child class’s constructor, we use super(firstName, lastName) to call the secondary constructor of the Parent class with the appropriate arguments. This ensures that the properties firstName and lastName are initialized in the Parent class.
if you run this program, you will see this output
Parent Secondary Constructor Called
Child Secondary Constructor Called
Name: Alice Smith, Age: 30