Constructors & init block in Kotlin
Amit Nadiger
Polyglot(Rust??, C++ 11,14,17,20, C, Kotlin, Java) Android TV, Cas, Blockchain, Polkadot, UTXO, Substrate, Wasm, Proxy-wasm,AndroidTV, Dvb, STB, Linux, Engineering management.
In Kotlin, constructors are special functions used for initializing an instance of a class. When an object is created, the constructor is called automatically to set the initial state of the object.
When we speak about constructors in Koltin we need to talk about below : primary constructor, secondary constructor, and anonymous constructor.
lets see each of them one by one here :
The primary constructor is a part of the class header and it can be defined with or without arguments. It is declared after the class name and it is the only constructor which can directly access the class properties.
Please note that, it is not possible to have multiple primary constructors in a class in Kotlin.
We can create a primary constructor in two ways:
Code Example:
class Person(firstName: String, lastName: String) {
init {
println("FirstName: $firstName")
println("LastName: $lastName")
}
? ? // Rest of the class code
}
2. Explicit Primary Constructor:
Code Example:
class Person constructor(firstName: String, lastName: String) {
? ? init {
? ? ? ? // Additional logic or initialization
? ? }
? ? // Rest of the class code
}
Both approaches achieve the same result of creating a primary constructor. The choice between them depends on whether you need to include additional logic or initialization in the constructor body. The implicit primary constructor is simpler and more concise, while the explicit primary constructor provides more flexibility when additional functionality is required.
In Kotlin, the constructor keyword is optional in the primary constructor. If the primary constructor does not have any annotations or visibility modifiers, you can omit the constructor keyword and directly declare the constructor parameters.
However, there are scenarios where you might need to use the constructor keyword in the primary constructor:
class Person private constructor(firstName: String, lastName: String) {
? ? // Rest of the class code
}
2. Annotating the constructor: If you want to add annotations to the constructor, you need to use the constructor keyword.
class Person @Inject constructor(firstName: String, lastName: String) {
? ? // Rest of the class code
}
In most cases, you can omit the constructor keyword in the primary constructor, as long as you don't need to specify the visibility or add annotations.
Advantages:
Disadvantages:
Suitable Scenario:
2. Secondary Constructor:
The secondary constructor is declared inside the class body and it can have zero or more parameters. It is used to provide additional initialization logic to the class.
Example:
class Person {
var name: String
var age: Int
constructor(name: String, age: Int) {
this.name = name
this.age = age
}
constructor() {
name = "" age = 0
}
}
In the above example, we have defined two secondary constructors. The first one takes two arguments and initializes the properties of the class, whereas the second one initializes the properties with default values.
Example 2:
class Person(val name: String, val age: Int) {
? ? constructor(name: String) : this(name, 0) // Secondary constructor with age set to 0
? ? constructor(age: Int) : this("", age) // Secondary constructor with name set to empty string
}
Please note that , it is possible to call primary constructor from the secondary constructor using the this keyword followed by the arguments that the primary constructor expects. This is a valid use case for calling a primary constructor from a secondary constructor in Kotlin.
class Person(val name: String, val age: Int) {
? ? constructor(name: String) : this(name, 0) // secondary constructor
}
In the above example, we have a primary constructor that takes two parameters name and age. We also have a secondary constructor that takes only one parameter name. The secondary constructor calls the primary constructor and passes the name parameter along with a default value of 0 for age. This way, we can use the primary constructor to initialize the properties of the class in a consistent way.
Advantages:
Disadvantages:
Suitable Scenario:
3. Default Constructor:
In Kotlin, If a class does not declare any constructor, then the default constructor is provided automatically by the compiler.
Example:
class Person {
var name: String = ""
var age: Int = 0
}
In the above example, we have not declared any constructor for the Person class. The compiler automatically generates a default constructor with no arguments. We have also initialized the properties with default values.
4. Anonymous constructor :
It is used in the case of anonymous classes, which are classes without a name. Anonymous classes are created by implementing an interface or extending a class and defining the implementation inside the curly braces. Anonymous constructors are used to initialize the properties of the anonymous class.
Here's an template :
领英推荐
val obj = object : SomeClass("param1", "param2") {
? ? init {
? ? ? ? // Initialization logic
? ? }
}
Example :
interface Shape {
? ? fun draw()
}
fun main() {
? ? val circle = object : Shape {
? ? ? ? var radius = 5
? ? ? ? init {
? ? ? ? ? ? println("Initializing circle")
? ? ? ? }
? ? ? ? override fun draw() {
? ? ? ? ? ? println("Drawing a circle with radius $radius")
? ? ? ? }
? ? }
? ? circle.draw()
}
/*
Initializing circle
Drawing a circle with radius 5
*/
In the above example, we define an interface Shape with a single method draw(). We then create an anonymous class that implements this interface using the object keyword, and define the implementation of the draw() method inside the curly braces.
We also define a property radius for the circle, and initialize it to 5. We use an anonymous constructor, defined with the init keyword, to print a message indicating that the circle is being initialized.
Finally, we create an instance of the anonymous class and call the draw() method on it, which prints a message indicating that a circle with a radius of 5 is being drawn.
Note that anonymous constructors can only access properties defined in the class or interface that is being implemented or extended, and cannot access properties or methods defined in the enclosing scope.
Advantages:
Disadvantages:
Suitable Scenario:
5. Init blocks :
The init block is used when there is some code that needs to be executed during the initialization of an instance of a class. It's particularly useful when you have a primary constructor and want to execute some initialization code that is not directly related to initializing the properties of the class.
init blocks are used to initialize the properties of a class. They are executed when an instance of the class is created. There can be one or more init blocks in a class, and they are executed in the order they are defined.
Here's an example of how init blocks work:
class Person(firstName: String, lastName: String) {
val fullName: String
init {
fullName = "$firstName $lastName"
println("Init block 1")
}
init {
println("Init block 2")
}
}
In the above example, Person class has two init blocks. The first block initializes the fullName property by concatenating firstName and lastName. The second block just prints a message. When an instance of Person is created, both init blocks are executed in the order they are defined.
Note that if you don't have a primary constructor, you can still use init blocks, but they must be defined inside a secondary constructor:
class Person {
? ? val name: String
? ? val age: Int
? ??
? ? constructor(name: String, age: Int) {
? ? ? ? this.name = name
? ? ? ? this.age = age
? ? ? ? println("A new person object has been created")
? ? }
}
In this case, the init block is used inside the secondary constructor to print a message to the console whenever a new Person object is created.
Advantages of init blocks:
Disadvantages of init blocks:
Is it possible to have both primary and secondary constructors at the same time ?
Yes, it is possible to have both primary and secondary constructors in Kotlin. The primary constructor is defined as part of the class header, while secondary constructors are defined using the constructor keyword.
Here's an example of a class with both primary and secondary constructors:
class Person(val name: String) {
? ??
? ? var age: Int = 0
? ??
? ? constructor(name: String, age: Int) : this(name) {
? ? ? ? this.age = age
? ? }
? ??
? ? fun printInfo() {
? ? ? ? println("Name: $name, Age: $age")
? ? }
}
fun main() {
? ? val person1 = Person("Amit ")
? ? person1.printInfo() // Output: Name: John, Age: 0
? ? val person2 = Person("Vinayak", 45)
? ? person2.printInfo() // Output: Name: Jane, Age: 25
}
/*
Op =>
Name: Amit , Age: 0
Name: Vinayak, Age: 45
*/
In this example, the primary constructor takes a name parameter and initializes the name property. The secondary constructor takes both name and age parameters, and it calls the primary constructor using the this keyword with the name parameter. Then, it sets the age property to the age parameter.
We can create objects of the Person class using either the primary constructor or the secondary constructor.
Calling superclass constructor:
Calling the superclass constructor is important because it allows the subclass to inherit the properties and behavior of its superclass. The superclass constructor is responsible for initializing the properties of the superclass, and by calling it, the subclass ensures that the superclass is properly initialized before any further initialization takes place in the subclass constructor.
For example, if a subclass extends a superclass that has some properties that need to be initialized before the subclass can use them, then the subclass constructor needs to call the superclass constructor to ensure that those properties are properly initialized. Similarly, if the superclass has some methods that the subclass needs to use, then those methods will only be available to the subclass if the superclass constructor has been called and the superclass has been properly initialized.
To call the superclass constructor in Kotlin, you can use the super keyword followed by the constructor parameters in parentheses. There are two ways to call the superclass constructor, depending on whether you are calling the primary or secondary constructor:
To call the primary constructor of the superclass, use the super keyword with the constructor parameters inside the parentheses of the derived class constructor, like this:
class DerivedClass(arg1: String, arg2: Int) : BaseClass(arg1, arg2) {
// class body
}
In this example, DerivedClass is calling the primary constructor of BaseClass with the arguments arg1 and arg2. The super keyword is followed by the arguments enclosed in parentheses.
2. Calling a secondary constructor:
To call a secondary constructor of the superclass, use the super keyword with the constructor parameters inside the parentheses of the derived class secondary constructor, like this:
class DerivedClass : BaseClass {
constructor(arg1: String, arg2: Int) : super(arg1, arg2) {
// constructor body
}
}
In the above example, DerivedClass is calling a secondary constructor of BaseClass with the arguments arg1 and arg2. The super keyword is used with the arg1 and arg2 enclosed in parentheses. Note that the super keyword must be the first statement in the body of the secondary constructor.
Defining default parameter values in a constructor in Kotlin
In Kotlin, default parameter values can be defined in constructors using the = operator followed by the default value. Here's an example:
class Person(val name: String, val age: Int = 18) {
// ...
}
In the above example, the age parameter has a default value of 18, so it is optional when creating a Person object. If no value is specified for age when creating a Person object, it will default to 18. Here's an example of creating a Person object with and without specifying the age parameter:
val person1 = Person("Amit") // age will be 18
val person2 = Person("Vinayak", 25) // age will be 25
Note that default parameter values can also be defined for functions in Kotlin using the same syntax.
Private constructor:
A private constructor is used to restrict the instantiation of a class from outside the class. This means that objects of the class cannot be created from outside the class, but can only be created within the class. There are several scenarios in which a private constructor can be useful:
Example:
class MyClass private constructor(val name: String) {
companion object {
fun create(): MyClass {
return MyClass("default")
}
}
}
In the above example, the primary constructor of MyClass is private, which means that it can only be accessed within the same class. The create() method in the companion object is used to create instances of the MyClass class. Since the primary constructor is private, the create() method is the only way to create instances of the class from outside of the class.
Thanks for reading till end . Please comment if you have any !