Kotlin 类 – Kotlin 构造函数

在本教程中,我们将讨论Kotlin的面向对象编程概念。我们将详细介绍Kotlin类。我们还将研究Kotlin的构造函数、访问修饰符和抽象类。

Kotlin课堂

kotlin class, kotlin constructor
class FirstClass {
}

以下是如何实例化该类的示例:

val firstClass =  FirstClass()
var new = FirstClass() //here new is the name of the var.

与Java不同,Kotlin中的new不是一个关键字。在Kotlin中,默认情况下,类是final的。因此,在Java中,上述定义的等效方式可能类似于以下代码:

public final class FirstClass {
}

因此,默认情况下,Kotlin中的类是不可继承的。为了使一个类非final,我们需要在其后面加上关键字open。

open class Me{
}

开放的注解允许其他类继承。

Kotlin 类示例

让我们创建一个带有几个函数和属性的类。我们将看到如何访问该类的函数和属性。此外,我们还将看到如何设置成员属性。

class User {

    var loggedIn: Boolean = false
    val cantChangeValue = "Hi"
    
    fun logOn() {
        loggedIn = true
    }
    
    fun logOff() {
        loggedIn = false
    }
}

fun main(args: Array<String>) {

    val user = User()
    println(user.loggedIn) //false
    user.logOn()
    println(user.loggedIn) //true
    user.logOff()
    println(user.loggedIn) //false
    user.cantChangeValue = "Hey" //won't compile. Can't modify a final variable.

}

主函数属于Test.kt类。要访问成员和函数,我们需要使用点运算符。不能再使用点运算符来设置val属性。

Kotlin的初始化

Kotlin的init块定义如下所示。

class User {
    
    init{
        print("Class instance is initialised.")
    }

    var loggedIn: Boolean = false
    val cantChangeValue = "Hi"

    fun logOn() {
        loggedIn = true
    }

    fun logOff() {
        loggedIn = false
    }
}

当类实例化时,init块中的代码将首先执行。每次实例化类时,init块都会运行,无论使用什么样的构造函数,下面我们将看到。一个类中可以编写多个初始化块。它们将按照下面的顺序依次执行。

class MultiInit(name: String) {

    init {
        println("First initializer block that prints ${name}")
    }

    init {
        println("Second initializer block that prints ${name.length}")
    }
}

fun main(args: Array<String>) {
    var multiInit = MultiInit("Kotlin")
}

//Following is printed in the log console.
//First initializer block that prints Kotlin
//Second initializer block that prints 6

使用下面所示的 also 函数,Kotlin 类可以在声明本身中打印属性。

class MultiInit(name: String) {
    val firstProperty = "First property: $name".also(::println)

    init {
        println("First initializer block that prints ${name}")
    }

    val secondProperty = "Second property: ${name.length}".also(::println)

    init {
        println("Second initializer block that prints ${name.length}")
    }
}

fun main(args: Array<String>) {

    var multiInit = MultiInit("Kotlin")
}

//Following gets printed.
//First property: Kotlin
//First initializer block that prints Kotlin
//Second property: 6
//Second initializer block that prints 6

Kotlin 构造函数

Kotlin的构造函数是用于初始化属性的特殊成员函数。与Java相比,Kotlin的构造函数的编写和结构有所不同。默认情况下,一个类具有以下空构造函数:

class Student {
    var name: String
    val age : Int

    init {
        name = "Anupam"
        age = 24
    }

    init {
        name = "Anupam Chugh"
        //age = 26
    }
}

fun main(args: Array<String>) {
    
    val student = Student()
    println("${student.name} age is ${student.age}")
    student.name = "Your"
    //student.age = 26 //won't compile. age is val
    println("${student.name} age is ${student.age}")

}

//Following is printed on the console:
//Anupam Chugh age is 24
//Your age is 24

主构造函数

Kotlin中的主构造函数是在类头中定义的,如下所示。

class User(var name: String, var isAdmin: Boolean) {

    init {
        name = name + " @ JournalDev.com"
        println("Author Name is $name. Is Admin? $isAdmin")
    }
}

主要的构造函数定义在类头部。我们已经在构造函数本身中定义了属性类型(val/var)。注意:除非声明为var,否则默认情况下构造函数参数是val。

class User(name: String, isAdmin: Boolean)

在上面的代码中,无法重新分配name和isAdmin。或者,我们也可以将构造函数的参数分配给类中的成员属性,如下所示。

class User(name: String, val isAdmin: Boolean) {

    var username  = name
    val _isAdmin = isAdmin

    init {
        username= username + " @ JournalDev.com"
        println("Author Name is $name. Is Admin? $_isAdmin")
    }
}

fun main(args: Array<String>) {

    var user = User("Anupam",false)
    user.isAdmin = true //won't compile since isAdmin is val
    user._isAdmin = true //won't compile. Same reason.
    user = User("Pankaj",true)
}

//Following is printed in the log console.
//Author Name is Anupam. Is Admin? false
//Author Name is Pankaj. Is Admin? true

Kotlin 构造函数的默认值

在Kotlin中,我们可以在构造函数本身中指定默认值,如下所示。

class User(name: String, var website: String = "JournalDev") {

    init {
        println("Author $name writes at $website")
    }

    init {
        website = website + ".com"
        println("Author $name writes at $website")
    }
}

fun main(args: Array<String>) {

    var user = User("Anupam","JournalDev")
    user = User("Pankaj","JournalDev")
}

//Following is printed on the console:
//Author Anupam writes at JournalDev
//Author Anupam writes at JournalDev.com
//Author Pankaj writes at JournalDev
//Author Pankaj writes at JournalDev.com

次要的构造函数

在类的主体内,通过添加关键字constructor在其前面来编写次要构造函数。下面的示例演示了相同的情况。

class Student {
    var name: String
    val age : Int

    constructor(name: String, age: Int)
    {
        this.name = name
        this.age = age
    }

    fun printDetails()
    {
        println("Name is $name and Age is $age")
    }

}

fun main(args: Array<String>) {

    var student = Student("Anupam", 24)
    student.printDetails()
}

//Following is printed in the console.
//Name is Anupam and Age is 24

在子类中,次要构造函数最常见的用途是在需要以不同方式初始化类时使用。如果该类包含一个主构造函数,次要构造函数必须在声明中引用它。使用关键字“this”来进行声明。

class Student(var name: String, val age: Int) {

    var skill: String

    init {
        skill = "NA"
    }

    constructor(name: String, age: Int, skill: String) : this(name, age) {
        this.skill = skill
    }

    fun printDetails() {
        if (skill.equals("NA"))
            println("Name is $name and Age is $age")
        else
            println("Name is $name and Age is $age Skill is $skill")
    }
}

//Following is printed in the log console:
//Name is Anupam and Age is 24
//Name is Anupam and Age is 24 Skill is Kotlin

初始化块用于初始化成员属性技能。次要构造函数使用”this”关键字委托给主构造函数。

自定义的获取器和设置器

直到现在,我们通过对类的实例使用点运算符来访问和修改属性。让我们使用set和get语法来看看如何自定义访问。

class Name{
    var post: String = "default"
    set(value) {if(!post.isNotEmpty()) {
        throw IllegalArgumentException(" Enter a valid name")
    }
                field = value
                print(value)
    }

}

fun main(args: Array<String>) {

    var name = Name()
    name.post = "Kotlin Classes"
    name.post = ""
    name.post = "Kotlin Data Classes Our Next Tutorial"


}

以下内容被打印在log控制台中:

Kotlin Classes

Exception in thread "main" java.lang.IllegalArgumentException:  Enter a valid name
	at Name.setPost(Test.kt:16)
	at TestKt.main(Test.kt:78)

在setter中,字段变量保存了旧值。让我们添加一个getter。

class Name{
    var post: String = "default"
    set(value) {if(!post.isNotEmpty()) {
        throw IllegalArgumentException(" Enter a valid name")
    }
                field = value
    }
    get() {
        return field.capitalize()
    }

}

fun main(args: Array<String>) {

    var name = Name()
    name.post = "kotlin classes"
    println(name.post)
    name.post = "kotlin data Classes our next Tutorial"
    println(name.post)

}

//Following is printed:
//Kotlin classes
//Kotlin data Classes our next Tutorial

capitalize()方法将字符串的第一个字母大写。注意:如果属性是val,则设置方法将无法编译通过。

Kotlin 可见性修饰符

  • Public : Any class, function, property, interface, or object that has this modifier is visible and can be accessed from anywhere.
  • Private: A class/function defined with this modifier can be only accessed within the same file. A member/property in a class/function with this modifier can be only accessed within that block.
  • Protected : This modifier is same as private, except that it allows visibility and access within subclasses.
  • Internal: A class/interface/function with this modifier is accessible only within the same module.

可见性修饰符同样适用于构造函数。将修饰符分配给主构造函数需要在类头中的构造函数旁指定关键字constructor。

class Student private constructor (var name: String, val age: Int) {

    var skill: String

    init {
        skill = "NA"
    }

    constructor(name: String, age: Int, skill: String) : this(name, age) {
        this.skill = skill
    }

    fun printDetails() {
        if (skill.equals("NA"))
            println("Name is $name and Age is $age")
        else
            println("Name is $name and Age is $age Skill is $skill")
    }
}

fun main(args: Array<String>) {

    var student = Student("Anupam",24,"Kotlin")
    student.printDetails()
}

//prints
//Name is Anupam and Age is 24 Skill is Kotlin

私有构造函数不能在类外部调用。在上述代码中,我们只能使用辅助构造函数在不同的函数中实例化该类。

Kotlin的抽象类

与Java类似,Kotlin中使用abstract关键字来声明抽象类。抽象类不能被实例化,但可以被子类继承。默认情况下,抽象类的成员都是非抽象的,除非另有声明。

abstract class Person(name: String) {

    init {
        println("Abstract Class. init block. Person name is $name")
    }

    abstract fun displayAge()
}

class Teacher(name: String): Person(name) {

    var age : Int

    init {
        age = 24
    }

    override fun displayAge() {
        println("Non-abstract class displayAge function overridden. Age is $age")
    }
}

fun main(args: Array<String>) {

    val person = Teacher("Anupam")
    person.displayAge()

}

//Following is printed in the console.
//Abstract Class. init block. Person name is Anupam
//Non-abstract class. Age is 24

注意:抽象类默认是开放的。所以不需要添加open修饰符来允许子类化。override关键字用于在子类中重写方法。在本教程中,我们已经介绍了Kotlin类的基础知识。还有很多其他内容,如数据类、密封类、继承等等。我们将在接下来的教程中涵盖它们。参考资料:Kotlin文档。

发表回复 0

Your email address will not be published. Required fields are marked *