Kotlin Classes, Objects, Constructors and Initializers

Classes and Objects are the central concepts in any Object Oriented Programming(OOP) language.

A class is a blueprint/template for creating objects of similar type. The objects contain state in the form of member variables (properties) and behavior in the form of member functions (methods).

Classes

You can create a Class in Kotlin using the class keyword -

class Person {
}

The curly braces can be omitted if the class has no body -

class Person

This is the simplest class that you can have in Kotlin. You can create an object/instance of the above the class using its default constructor like so -

val person = Person()

Notice that, unlike other object-oriented programming languages like Java, You don’t need to use the new keyword to instantiate a class in Kotlin. In fact, new is not a keyword in Kotlin.

Properties

An empty class is not that useful in real world. Let’s add some properties to our class now.

You can declare properties (member variables) in the class body similar to how you declare any other variable in Kotlin. These properties can be declared as mutable, using the var keyword or read-only using the val keyword -

class Person {
	// Properties or Member Variables
    var firstName: String
    var lastName: String
}

In the above class, we have declared two mutable properties. Note that, the code above won’t compile because we haven’t specified how these properties will get initialized when we create an object of the class.

We can provide default values to the properties to avoid compilation error like so -

class Person {
    var firstName: String = "Guest"
    var lastName: String = ""
}

But for initializing them to different values while creating an object, we need to define a constructor in the class.

Constructors

A constructor is a special kind of member function that is used to initialize the state/properties of newly created objects of the class. It is invoked when you create an instance of the class.

Every class needs to have a constructor. If you don’t declare one yourself, the compiler generates a default constructor.

There are two types of constructors in Kotlin -

  • Primary Constructor
  • Secondary Constructor

A Kotlin class can have one Primary constructor and one or more secondary constructors.

1. Primary Constructor

The Primary constructor is part of the class header and declared after the class name like so -

class Person constructor(firstName: String, lastName: String) {
}

It takes a list of comma-separated parameters with their type modifiers. These parameters are used to initialize the member variables of the class.

You can omit the constructor keyword from the primary constructor if it does not have any annotations or visibility modifiers (public, private or protected) -

class Person(firstName: String, lastName: String) {
}

Initializer Block

Let’s now see how to initialize the properties of a class with the parameters passed to the primary constructor.

The primary constructor cannot contain any code. So all the initialization logic is written inside an initializer block which is prefixed with the init keyword -

class Person(_firstName: String, _lastName: String) {
    // Member Variables (Properties) of the class
    var firstName: String
    var lastName: String

    // Initializer Block
    init {
        this.firstName = _firstName
        this.lastName = _lastName

        println("Initialized a new Person object with firstName = $firstName and lastName = $lastName")
    }
}

I have prefixed the parameter names in the primary constructor with an underscore(_) to distinguish them from the member variables of the class. It’s not required though, since we’re using this keyword anyway in the init block.

Note that, instead of initializing the properties in the init block, you can directly initialize them in the class body itself like this -

class Person (_firstName: String, _lastName: String) {
    // Member Variables (Properties) of the class
    var firstName: String = _firstName
    var lastName: String = _lastName

    // Initializer Block
    init {
        println("Initialized a new Person object with firstName = $firstName and lastName = $lastName")
    }
}

You can create an instance of the above class using the primary constructor like this -

val p = Person("Jack", "Dorsey")

Kotlin’s concise syntax for declaring and initializing properties

Kotlin has a concise syntax for declaring properties and initializing them from the primary constructor -

class Person(var firstName: String, var lastName: String) {
    // Initializer Block
    init {
        println("Initialized a new Person object with firstName = $firstName and lastName = $lastName")
    }
}

The above class is equivalent to the class we saw in the previous section.

That’s really cool no? This syntax allows us to directly declare properties inside the primary constructor using the var or val keyword, and also frees us from writing the initialization boilerplate code.

Default Values in the Constructor

We can also provide default values for the properties of the class right inside the constructor -

class Person(var firstName: String = "Guest", var lastName: String = "") {
    // Initializer Block
    init {
        println("Initialized a new Person object with firstName = $firstName and lastName = $lastName")
    }
}

This allows us to omit the firstName and lastName parameters while creating an object. So all of the following calls are valid now -

val person1 = Person("Jack", "Dorsey")
val person2 = Person("Jack")
val person3 = Person()

The default value for a parameter is used if no value is supplied for that parameter while instantiating an object.

2. Secondary Constructor

Apart from the primary constructor, you can also declare one or more secondary constructors in the class. Secondary constructors are prefixed with the constructor keyword and declared inside the class body -

class Person {
    // Properties
    var firstName: String
    var lastName: String
    
    // Secondary Constructor
    constructor(firstName: String, lastName: String)  {
        this.firstName = firstName
        this.lastName = lastName
    }
}

You can also combine both primary constructor and secondary constructor in the same class. One thing to note here is that every secondary constructor must call the primary constructor, either directly or indirectly via another secondary constructor.

In the following example, we have declared a primary constructor as well as a secondary constructor. The secondary constructor calls the primary constructor using this keyword -

class Person(var firstName: String, var lastName: String) {
    var age: Int? = null

    // Secondary Constructor
    constructor(firstName: String, lastName: String, age: Int): this(firstName, lastName)  {
        this.age = if(age > 0) age else throw IllegalArgumentException("Age must be greater than zero")
    }
}

You can now instantiate an object either using the primary constructor or the secondary constructor -

// Calls the primary constructor (Age will be null in this case)
val person1 = Person("Bill", "Gates")

// Calls the secondary constructor
val person2 = Person("Jeff", "Bezos", 53) 

You can also have multiple overloaded secondary constructors in the class -

class Person(var firstName: String, var lastName: String) {
    var age: Int? = null
    var phoneNumber: String? = null
    
    // Secondary Constructor
    constructor(firstName: String, lastName: String, age: Int): this(firstName, lastName)  {
        this.age = if(age > 0) age else throw IllegalArgumentException("Age must be greater than zero")
    }

    // Secondary Constructor
    constructor(firstName: String, lastName: String, age: Int, phoneNumber: String): 
            this(firstName, lastName, age)  {
        this.phoneNumber = phoneNumber
    }
}

Notice how the last secondary constructor calls the first one using this keyword.

Visibility Modifiers

Visibility modifiers help us restrict the accessibility of classes, objects, constructors, functions or properties.

There are four types of visibility modifiers in Kotlin - public, private, protected and internal. The default visibility for everything is public.

Following are the access scope of these visibility modifiers -

  1. public - Anything that is declared public is accessible everywhere.

  2. private - A top-level function or class that is declared private can be accessed only within the file where it is declared.

    Any member function, constructor, or property that is declared private is visible only within the class where it is declared.

  3. protected - Any property or function declared as protected is accessible in the same class and its subclasses.

  4. internal - Accessible within the same module. A module is a set of files compiled together (ex - a maven project or a gradle module)

Accessing and Setting Properties

Unlike Java, we don’t need to define getters and setters for getting and setting the properties of an object.

Kotlin automatically generates an implicit getter and a setter for mutable properties, and a getter (only) of read-only properties.

You can access the properties of an object using the dot(.) notation like this -

val person = Person("Sundar", "Pichai")
println(person.firstName) // Sundar
println(person.lastName) // Pichai

For setting properties, just assign them to the new value -

val person = Person("Steve", "Wozniak")
person.lastName = "Jobs"
println("Name = ${person.firstName} ${person.lastName}") // Steve Jobs

Notice that, In Kotlin, we don’t need to call the getter and setter methods for accessing and setting the properties - as we do in Java. Kotlin internally calls the default (implicit) getters/setters of the properties. So the line person.lastName = "Jobs" in Kotlin is same as person.setLastName("Jobs") in Java.

Let’s see another example with read-only properties -

class Student (val rollNumber: Int, 
               val name: String)

val student = Student(1, "John")
println(student.rollNumber)
println(student.name)

student.name = "Jack" // Error: Val can not be assigned

As expected, Kotlin disallows assignment to val(read-only) properties.

Conclusion

That’s all folks. In this article, you learned the basics of Kotlin classes, objects, primary constructors, secondary constructors and initializer blocks.

Thanks for reading. Stay tuned for more articles on Kotlin.