Trong bài viết này, bạn sẽ tìm hiểu về các hàm tạo trong Kotlin (cả các hàm tạo chính và phụ) cũng như các khối khởi tạo thông qua việc tìm hiểu các ví dụ.

Hàm tạo là một cách thức ngắn gọn để khởi tạo các thuộc tính của class.

Đây là một hàm thành viên đặc biệt và nó được gọi khi một đối tượng được khởi tạo (tạo). Tuy nhiên, cách các hàm này làm việc trong Kotlin có một số sự khác nhau.

Trong Kotlin, có hai hàm tạo:

  • Hàm tạo chính – đây là một cách ngắn gọn để khởi tạo một class
  • Hàm tạo thứ cấp – cho phép bạn đặt logic khởi tạo bổ sung

1. Hàm tạo chính

Hàm tạo chính là một phần trong header của class. Dưới đây là một ví dụ:

class Person(val firstName: String, var age: Int) {
    // class body
}

Phần code được bao quanh bởi dấu ngoặc đơn là hàm tạo chính : (val firstName: String, var age: Int).

Hàm tạo đã khai báo hai thuộc tính: firstName (thuộc tính chỉ đọc vì nó được khai báo bằng từ khóa val) và age (thuộc tính đọc-ghi vì nó được khai báo bằng từ khóa var).

Ví dụ: hàm tạo chính

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

fun main(args: Array<String>) {

    val person1 = Person("Joe", 25)

    println("First Name = ${person1.firstName}")
    println("Age = ${person1.age}")
}

class Person(val firstName: String, var age: Int) {

}

Khi bạn chạy chương trình, kết quả sẽ là:

First Name = Joe
Age = 25

Khi đối tượng của class Person được tạo, các giá trị “Joe” và 25 được thông qua giống như khi ta coi Person là một hàm.

Hàm tạo này khởi tạo 2 thuộc tính firstName và age của đối tượng person1 lần lượt đến các giá trị “Joe” và 25.

Ngoài ra, có nhiều cách khác để sử dụng các hàm tạo chính.

1.1. Hàm tạo chính và khối khởi tạo

Hàm tạo chính có cú pháp bị ràng buộc và không thể chứa bất kỳ code.

Để đặt code khởi tạo (không kể phần code để khởi tạo thuộc tính), ta sử dụng khối khởi tạo. Nó có tiền tố là từ khóa init. Hãy sửa đổi ví dụ trên với khối khởi tạo:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

fun main(args: Array<String>) {
    val person1 = Person("joe", 25)
}

class Person(fName: String, personAge: Int) {
    val firstName: String
    var age: Int

    // initializer block
    init {
        firstName = fName.capitalize()
        age = personAge

        println("First Name = $firstName")
        println("Age = $age")
    }
}

Khi bạn chạy chương trình, kết quả sẽ là:

First Name = Joe
Age = 25

Ở đây, thông số fName và personAge bên trong dấu ngoặc đơn lần lượt chấp nhận các giá trị “Joe”và 25 tương ứng khi đối tượng person1 được tạo ra. Tuy nhiên, fName và personAge được sử dụng mà không cần từ khóa var hoặc val, và chúng cũng không phải là các thuộc tính của class Person.

Class Person có hai thuộc tính firstName và age được khai báo.

Khi đối tượng person1 được tạo, phần code bên trong khối khởi tạo được thực hiện. Khối khởi tạo không chỉ khởi tạo các thuộc tính của nó mà còn in chúng ra.

Ta cũng có thể làm theo cách sau:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

fun main(args: Array<String>) {
    val person1 = Person("joe", 25)
}

class Person(fName: String, personAge: Int) {
    val firstName = fName.capitalize()
    var age = personAge

    // initializer block
    init {
        println("First Name = $firstName")
        println("Age = $age")
    }
}

Để phân biệt tham số hàm tạo và thuộc tính hàm tạo, người ta sử dụng các tên khác nhau (fName và firstName, personAge và age). Ta thường hay sử dụng _firstName và _age thay vì dùng các tên hoàn toàn khác biệt cho các tham số hàm tạo. Ví dụ:

class Person(_firstName: String, _age: Int) {
    val firstName = _firstName.capitalize()
    var age = _age

    // initializer block
    init {
        ... .. ...
    }
}

1.2. Giá trị mặc định trong hàm tạo chính

Bạn có thể cung cấp giá trị mặc định cho các tham số của hàm tạo (tương tự như việc cung cấp các đối số mặc định cho các hàm ). Ví dụ:

fun main(args: Array<String>) {

    println("person1 is instantiated")
    val person1 = Person("joe", 25)

    println("person2 is instantiated")
    val person2 = Person("Jack")

    println("person3 is instantiated")
    val person3 = Person()
}

class Person(_firstName: String = "UNKNOWN", _age: Int = 0) {
    val firstName = _firstName.capitalize()
    var age = _age

    // initializer block
    init {
        println("First Name = $firstName")
        println("Age = $age\n")
    }
}

Khi bạn chạy chương trình, kết quả sẽ là:

First Name = Joe
Age = 25

person2 is instantiated
First Name = Jack
Age = 0

person3 is instantiated
First Name = UNKNOWN
Age = 0

2. Hàm tạo phụ trong Kotlin

Trong ngôn ngữ lập trình Kotlin, một class cũng có thể chứa một hoặc nhiều hàm tạo phụ. Chúng được tạo bằng cách sử dụng từ khóa constructor.

Các hàm tạo phụ thường không phổ biến trong Kotlin. Việc sử dụng hàm tạo phụ sẽ hiệu quả khi bạn cần mở rộng một class cung cấp nhiều hàm tạo, mà các hàm tạo này khởi tạo class đó theo các cách khác nhau.

Dưới đây là cách tạo một hàm tạo phụ trong Kotlin:

class Log {
    constructor(data: String) {
        // some code
    }
    constructor(data: String, numberOfData: Int) {
        // some code
    }
}

Ở đây, class Log có hai hàm tạo phụ, nhưng không có hàm tạo chính.

Bạn có thể mở rộng class theo cách dưới đây:

class Log {
    constructor(data: String) {
        // code
    }
    constructor(data: String, numberOfData: Int) {
        // code
    }
}

class AuthLog: Log {
    constructor(data: String): super(data) {
        // code
    }
    constructor(data: String, numberOfData: Int): super(data, numberOfData) {
        // code
    }
}

Ở đây, các hàm tạo của class dẫn xuất AuthLog gọi các hàm tạo tương ứng của class cơ sở Log. Để làm điều đó, ta sử dụng hàm super().

Trong Kotlin, ta cũng có thể gọi một hàm tạo từ một hàm tạo khác ở trong cùng một class (giống như trong Java) bằng cách sử dụng hàm this().

class AuthLog: Log {
    constructor(data: String): this(data, 10) {
        // code
    }
    constructor(data: String, numberOfData: Int): super(data, numberOfData) {
        // code
    }
}

Khi bạn chạy chương trình, kết quả sẽ là:

Ví dụ: Hàm tạo phụ trong Kotlin

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

fun main(args: Array<String>) {

    val p1 = AuthLog("Bad Password")
}

open class Log {
    var data: String = ""
    var numberOfData = 0
    constructor(_data: String) {

    }
    constructor(_data: String, _numberOfData: Int) {
        data = _data
        numberOfData = _numberOfData
        println("$data: $numberOfData times")
    }
}

class AuthLog: Log {
    constructor(_data: String): this("From AuthLog -> " + _data, 10) {
    }

    constructor(_data: String, _numberOfData: Int): super(_data, _numberOfData) {
    }
}

Khi bạn chạy chương trình, kết quả sẽ là:

From AuthLog -> Bad Password: 10 times

Lưu ý: Hàm tạo phụ phải khởi tạo class cơ sở hoặc ủy quyền cho hàm tạo khác (như trong ví dụ trên) nếu như class không có hàm tạo chính.

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!