kotlin的属性与字段

属性与字段

在kotlin中声明属性可以用var,val声明,其中var声明的是一个可变的变量,val声明是只读的,不可修改

image

在IDE中,给val声明的属性赋值会报错

属性的get和set方法

在kotlin中其实也是有get和set方法的,不过一般都是默认实现的,这个比java方便

var [: ] [= ]
    []
    []

其初始器(initializer)、getter 和 setter 都是可选的。属性类型如果可以从初始器 (或者从其 getter 返回值,如下文所示)中推断出来,也可以省略。

var allByDefault: Int? // 错误:需要显式初始化器,隐含默认 getter 和 setter
这种展示是不可以的,必须要在`init`中初始化才可以
var initialized = 1 // 类型 Int、默认 getter 和 setter

这个的意思就是一个属性必须要有已经初始化之后才会有默认的get和set方法,如果没有初始化,IDE就会报错

get和set的多种实现


    var ag1: Int = 0
    
        get() {
            return field
        }
        set(value) {
            field = value
        }

幕后字段

// 错误的示范
class NetworkConfig(override var i: Int = 0) : Base() {

    init {
        ag = 0
    }

    var ag1: Int = 0

        get() {
            return ag1
        }
        set(value) {
            ag1 = value
        }

    fun ss() {
//        ag = 99
    }
}

在这里我们好似是把get和set的值赋值到了属性上,但是如果我们这样写就会陷入死循环,我们在set方法里给属性赋值,在kotlin里就会再次调用属性的set方法,陷入循环,

// 错误的示范
class NetworkConfig(override var i: Int = 0) : Base() {

    init {
        ag = 0
    }

    var ag1: Int = 0

        get() {
            return ag1(再次调用get方法)
        }
        set(value) {
            ag1 = value(再次调用说set方法)
        }

    fun ss() {
//        ag = 99
    }
}

在 Kotlin 类中不能直接声明字段。然而,当一个属性需要一个幕后字段时,Kotlin 会自动提供。这个幕后字段可以使用field标识符在访问器中引用:

幕后属性

如果你的需求不符合这套“隐式的幕后字段”方案,那么总可以使用 幕后属性(backing property):

private var _table: Map? = null
public val table: Map
    get() {
        if (_table == null) {
            _table = HashMap() // 类型参数已推断出
        }
        return _table ?: throw AssertionError("Set to null by another thread")
    }

编译期常量

如果只读属性的值在编译期是已知的,那么可以使用 const 修饰符将其标记为编译期常量。 这种属性需要满足以下要求:

位于顶层或者是 object 声明 或 companion object 的一个成员
以 String 或原生类型值初始化
没有自定义 getter
这些属性可以用在注解中:

const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"
//作用和final相似,要不就是在一个类的顶层,要不就是静态属性
@Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { …… }

延迟初始化属性与变量

一般地,属性声明为非空类型必须在构造函数中初始化。 然而,这经常不方便。例如:属性可以通过依赖注入来初始化, 或者在单元测试的 setup 方法中初始化。 这种情况下,你不能在构造函数内提供一个非空初始器。 但你仍然想在类体中引用该属性时避免空检测。

为处理这种情况,你可以用 lateinit 修饰符标记该属性:

public class MyTest {
    lateinit var subject: TestSubject

    @SetUp fun setup() {
        subject = TestSubject()
    }

    @Test fun test() {
        subject.method()  // 直接解引用
    }
}

该修饰符只能用于在类体中的属性(不是在主构造函数中声明的 var 属性,并且仅当该属性没有自定义 getter 或 setter 时),而自 Kotlin 1.2 起,也用于顶层属性与局部变量。该属性或变量必须为非空类型,并且不能是原生类型。

在初始化前访问一个 lateinit 属性会抛出一个特定异常,该异常明确标识该属性被访问及它没有初始化的事实。

所以我们在需要的时候可以检测这个属性是否初始化

if (foo::bar.isInitialized) {
    println(foo.bar)
}

此检测仅对可词法级访问的属性可用,即声明位于同一个类型内、位于其中一个外围类型中或者位于相同文件的顶层的属性。

你可能感兴趣的:(kotlin的属性与字段)