Kotlin基本知识四——构造方法

170 阅读3分钟

1.主函数方法

主构造方法:通常是主要而简洁的初始化类的方法,并且在类体外部声明

从构造方法:在类体内部声明

通用也允许在初始化语句块中添加额外的初始化逻辑。

(1)主构造方法

结构,如:class User(val nickname: String)

这段别括号围起来的语句块就叫做主构造方法。它主要有两个目的:表明构造方法的参数,以及定义使用这些参数初始化的属性

class User constructor(_nickname: String) {
    val nickname: String 
    
    // 初始化语句块
    init {
        nickname = _nickname
    }
}

两个新的Kotlin关键字:constructorinit

constructor:用于开始一个主构造方法或从构造方法的声明。

init:用于引入一个初始化语句块。

init语句块包含了在类被创建时执行的代码,并会与主构造方法一起使用。因为主构造方法有语法限制,不能包含初始化代码。

上述代码也可如下表示:

  • 简化一:
// 带一个参数的主构造方法
class User(_nickname: String) {
    // 用参数来初始化属性
    val nickname = _nickname
}
  • 简化二:
//“val”意味着相应的属性会用构造方法的参数来初始化
class User(val nickname: String)

构造方法参数声明一个默认值

class User(val nickname: String, 
           val isSubscribed: Boolean = true)

创建一个类的实例。只需要直接调用构造方法,不需要new关键字:

// 为isSubscribed参数使用默认值“true”
>>>val alice = User("Alice")
>>>println(alice.isSubscribed)
true

当前类具有一个父类,主构造方法同样需要初始化父类。可以通过在基类列表的父类引用中提供父类构造方法参数的方式来做到这点:

open class User(val nickname: String) { ... }

class TwitterUser(nickname: String): User(nickname) { ... }

同Java一样,Kotlin的类也会自动生成一个不做任何事情的默认构造方法

示例:

open class Button

class RadioButton: Button()

父类名称后面需要一个空的括号。注意与接口的区别接口没有构造方法

类不被其他代码初始化,必须把构造方法标记为private

// 这个类有一个private构造方法
class Secretive private constructor() {}

因为Secretive类只有一个private的构造方法,这个类外部的代码不能实例化它。

(2)构造方法:用不同的方式来初始化父类

open class View {
    // 从构造方法
    // 调用父类
    constructor(ctx: Context): super(ctx) {
        // some code
    }
    
    // 从构造方法
    constructor(ctx: Context, attr: AttributeSet): super(ctx, attr) {
        // some code
    }
}

(3)实现在接口中声明的属性

interface User {
    val nickname: String
}

class PrivateUser(override val nickname: String): User
class SubscribingUser(val email: String): User {
    // 自定义getter
    override val nickname: String
        get() = email.substringBefore('@')
}
class FackbookUser(val accountId: Int): User {
    // 属性初始化
    override val nickname = getFacebookName(accountId)
}

除了抽象属性声明外,接口还可以包含具有getter和setter的属性,只要它们没有引用一个支持字段(支持字段需要的在接口中存储状态,而这是不允许的)。

(4)通过getter或setter访问支持字段

class User(val name: String) {
    var address: String = "unspecified"
        set(value: String) {
            // 读取支持字段的值
            println("""Address was changed for $name:
                "$field" -> "$value".""".trimIndent())
            // 更新支持字段
            field = value
        }
}

在setter的函数体中,使用了特殊的标识符field来访问支持字段的值。 在getter中,只能读取值;而在setter中,既能读取它又能修改它。

访问器的可见性默认与属性的可见性相同。 但是如果需要可以通过在get和set关键字前放置可见性修饰符的方式来修改它。

class LengthCounter {
    var counter: Int = 0
        // 不能在类外部修改这个属性
        private set
    
    fun addWord(word: String) {
        counter += word.length
    }
}

编译器生成一个默认可见性的getter方法,并且将setter的可见性修改为private