这篇文章是一时兴起想写的,由于我发现我对Kotlin的属性理解一直有误java
首先咱们要搞清楚在 Java 中属性是什么,在 Java 中类的属性不是指一个字段,而是一个字段和它的get、set方法加在一块儿才算一个属性,好比:android
class Person {
int age;
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age
}
}
复制代码
而若是不给这个 name 写get、set方法,它就只是一个 field,能够称它为 字段 或者 域。bash
若是上面的代码用kotlin翻译一下:app
class Person {
var age = 0
}
复制代码
能够对比出,Kotlin里不须要额外的get、set方法,固然你也写不了,由于 Kotlin 已经默认实现了get、set,因此在Kotlin里,咱们写不出 field。编辑器
前面说 Kotlin 中不能写 field,可是咱们不少时候必需要用到 field,好比你复写一个属性的set方法函数
var age = 0
set(value){
age = value + 1
}
复制代码
若是这样写实际上是会发生递归,没法赋值成功 ui
var age = 0
set(value){
field = value + 1
}
复制代码
这里出现了一个 field 的东西能够访问和赋值,这个东西就是 Kotlin 的幕后字段(Backing Field)
咱们能够简单地理解为,Kotlin 没有明面上的 field,可是它存在于幕后this
class Person{
private var _age =0
var age:Int
get() = _age
set(value) {
_age = value
}
}
复制代码
当咱们声明一个 var 为私有时,好比上面的_age,咱们叫它 幕后属性 ,虽然它看起来不须要get、set方法,可是其实仍然是有的,只不过它的get、set方法都被声明为 private 了spa
固然咱们这里不是想讨论幕后属性,而是要讨论一下这个 age 是个什么玩意,是一个成员属性吗,其实经过字节码就能够知道,这里的Person类实际并不存在age这个成员,它只是帮你生成了对_age的两个public final的get和set方法翻译
// access flags 0x2
private I _age
// access flags 0x11
public final getAge()I
L0
LINENUMBER 28 L0
ALOAD 0
复制代码
和你本身直接写一个
fun getAge() = _age
复制代码
是如出一辙的
再举一个例子:
var View.topPadding: Int
inline get() = paddingTop
set(value) = setPadding(paddingLeft, value, paddingRight, paddingBottom)
复制代码
这是从anko的拷出来一段代码,经过这个扩展成员,咱们能够直接对某个 View 的 PaddingTop 进行修改和读取,虽说是成员,可是咱们把一段字节码拿出来看一下:
// access flags 0x19
public final static getTopPadding(Landroid/view/View;)I
@Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0****
...
// access flags 0x19
public final static setTopPadding(Landroid/view/View;I)V
@Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
复制代码
很明显,这里就是直接生成了两个静态函数getTopPadding
和setTopPadding
,并非真的为View这个类添加了一个成员,那这个东西到底什么呢?咱们把上面的代码稍微改一下:
var View.topPadding: Int = 0
inline get() = paddingTop
set(value) = setPadding(paddingLeft, value, paddingRight, paddingBottom)
复制代码
给这个成员加个默认值,能够看到,编辑器报错了
在Kotlin中一个 property 无论有没有 backing field 都称之为 property,而在 Java 中 field + get、set方法一块儿才能是一个 property。
若是咱们从Java 的角度去看一个没有 backing field 的 property,能够理解为 Kotlin 对 以get、set开头这样的函数的语法糖,这种语法糖有什么用呢?我的以为是为了DSL语法服务的,仍是以上面那个topPadding为例,当你在用 DSL 语法设置一个view的时候,好比:
view.apply {
background = getDrawable(R.drawable.bg)
visibility = View.INVISIBLE
...
}
复制代码
前面都是一个属性等于一个值,这个时候下面跟上 topPadding = xxx
,语义十分清晰连贯,若是这里忽然用一个 setTopPadding(this,xxx)
,不只代码不美观,并且打断了阅读代码和编写代码的人的思惟上的连贯性。
以上就是我对 Kotlin 的 Property 的理解