Kotlin Backing Field

2019-10-30  本文已影响0人  JCYDSHANKS

备用字段?
幕后字段?
支持字段?
后端域变量?
翻译这么多种,其实都是一个意思 Backing Field

找到一些关于他的描述:

那么这里有一些关于field的特点:

在setter函数体中,使用了特殊标记符field来访问字段的值
在getter中,只能读取该值。
在setter中,既能读取也能修改它。

//使用field关键字
public var fieldProp = ""
    get() = field
    set(value) {
        field = value
    }
//自定义不使用field 不生成:
val isEmpty: Boolean
    get() = this.size == 0
//默认访问器 生成:
val Foo.bar = 1

如果在类中定义一个成员变量,kotlin将自动生成默认的setter/getter方法。
kotlin声明get/set的方式为

  var name: String? = null
        set(value) {
            field = value
        }
        get() = field

这里使用了field,如果不使用field,会这么写:

  var name: String? = null
        set(value) {
            name = value
        }
        get() = name

但是这么写,对这个属性进行赋值并取值时出现了一些问题:


图片1.png

在setter方法中对属性进行赋值和取值时,会调用自身,出现了递归调用。

这个时候field就可以解决这个问题了,backing field的作用域在当前属性的setter/getter方法中,以中间变量的形式,来解决了递归问题。

在拓展属性中

在拓展属性中,是没有field这个字段的


图片2.png

转换一下写法


图片3.png

按照正常的写法,这里报错。说明拓展属性没有field。
如果把这个拓展常量变成属性,会提示属性必须初始化:


图片4.png

那我们直接初始化试试


图片5.png

直接赋值进行初始化又报错了: 拓展属性不能初始化,因为他没有支持字段 (backing field)。
为什么拓展属性不能初始化?这个问题可以转换为 为什么拓展属性没有支持字段?

官方说:

实际上,扩展并不会真正地往类中插入成员变量。因此,我们没有一个有效的方式让一个扩展属性拥有backing field,这就是扩展属性不允许被初始化的原因。

那么拓展属性到底是什么?
Kotlin 可以对一个类的属性和方法进行扩展,且不需要继承或使用装饰器模式。扩展是一种静态行为,对被扩展的类代码本身不会造成任何影响。

因为不会对类的代码本身造成任何影响,所以扩展不会真正的往类中插入成员变量。

field的作用域是当前属性的访问器,而当前属性是与某个类的实例对应的,所以类中并没有这个属性,也就没有一个有效的方式让这个属性拥有backing field了。

访问属性的方式不依赖于它是否含有field,如果你显式地引用或者使用默认的访问器实现,编译器会为属性生成field。如果你提供了一个自定义的访问器实现并且没有使用field,支持字段将不会被呈现出来。

有时候不需要修改访问器的默认实现,但是需要修改它的可见性:

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

在接口中

在接口中,可以包含具有setter/getter的属性,只要他们没有引用一个backing field,
backing field需要在接口中存储状态,而这是不被允许的


图片6.png
图片7.png
支持属性:功能与backing field相似,能达到相同的效果:
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
    get() {
        if (_table == null) {
            _table = HashMap() // 参数类型是自动推导
        }
        return _table ?: throw AssertionError("Set to null by another thread")
    }
参考

https://medium.com/@agrawalsuneet/backing-field-in-kotlin-bd9c2d5b6da5
https://juejin.im/post/5a79c053f265da4e6e2bad37
https://blog.csdn.net/Strange_Monkey/article/details/82707242

上一篇 下一篇

猜你喜欢

热点阅读