深入Kotlin - 专项 - 幕后字段、幕后属性
2017-08-31 23:50
225 查看
幕后字段
Kotlin提供一个自动幕后字段,它可以通过
field 标志符访问。
那么幕后字段到底是什么?有什么用呢?首先来看一段代码:
class Person(val name:String){ val nameHash get() = name.hashCode() }
这里我们要知道
getter 和
setter 是什么,getter和setter是否一定与属性相关联,答案是否定的。
getter是从对象中获取特定的值,这个值完全可能是每次访问时临时计算的,也可能从其他对象那里得到的;
setter也可能是设置其他的对象;
具体我们可以看看下面的代码:
class Person(val name:String){ val nameHash:Int = 3 get() { field = 5 return 10 } fun out(){ println(nameHash) } } fun main(args: Array<String>) { val ts = Person("lxx") println(ts.nameHash) ts.out() }
运行输出,我们会看到输出两个10,看起来一切都没什么问题,别急,我们来看看它的字节码,可以反编译成java代码来看
public final class Person { private final int nameHash; @NotNull private final String name; public final int getNameHash() { this.nameHash = 5; //对应上面的field = 5 return 10; } public final void out() { int var1 = this.getNameHash(); System.out.println(var1); } @NotNull public final String getName() { return this.name; } public Person(@NotNull String name) { Intrinsics.checkParameterIsNotNull(name, "name"); super(); this.name = name; this.nameHash = 3; //对应上面的val nameHash:Int = 3 } }
从上面可以看出:getter方法被翻译成了getNameHash()方法
我们可以看出:this.nameHash先被赋值成3,而后又被赋值成5
我们通过ts.nameHash和out()方法输出nameHash的值都是10是因为这两种方法最终都是调用getNameHash()方法,而它的返回值是10,但是实际上nameHash的值是重新赋值成了5
那么我们怎么来判断nameHash的实际值呢?看下面的代码:我们加了一个setter方法
class Person(val name: String) { var nameHash: Int = 3 get() { field = 5 return 10 } set(value) { when(field){ 3 -> println("field = 3") 5 -> println("field = 5") 10 -> println("field = 10") else -> println("field = $field ,value = $value") } } fun out() { println(nameHash) } } fun main(args: Array<String>) { val ts = Person("lxx") println(ts.nameHash) ts.out() ts.nameHash = 100 }
运行输出:field = 5
说明nameHash的实际值是5,来看看字节码就更清楚了
//只截取了setter方法 public final void setNameHash(int value) { String var2; switch(this.nameHash) { case 3: var2 = "field = 3"; System.out.println(var2); break; case 5: var2 = "field = 5"; System.out.println(var2); break; case 10: var2 = "field = 10"; System.out.println(var2); break; default: var2 = "field = " + this.nameHash + " ,value = " + value; System.out.println(var2); } }
从上面的例子可以看出
field幕后字段的作用。不使用field,实际变量并未被初始化,但是在Kotlin中可能不会后问题,应为setter和getter最终都会被转换成对应方法调用,
4000
但是在Java调用Kotlin的时候可能就会有问题了,当然这是猜测,具体暂时就不再深究了
幕后属性
了解了幕后字段,我们再来看看幕后属性。幕后属性是我们自己定义的,一般用于这种情况:
我们希望定义一个这样的变量
对外表现为只能读,不能写
对内表现可以任意读写
这在Java中的应该只能通过函数来做
那么,在Kotlin中呢?Kotlin中定义变量
val只能读,不能写
var任意读写
那么同一个变量,怎么实现两种情况呢,这里就要用上我们上面看到的,getter方法实际上是被翻译成了对于变量的函数。
看代码:
class Demo{ val size get() = _size private var _size:Int = 0 }
这里size是提供给对外的变量,_size是内部使用的,其实最后还是通过函数来控制的,不信可以看看字节码
public final class Demo { private int _size; public final int getSize() { return this._size; } }
这里_size就叫做幕后属性
其实幕后属性就是我们设计类属性时的一种实现方法而已
不同于field幕后字段是Kotlin内置提供给我们的
相关文章推荐
- 深入Kotlin - 专项 - 委托属性-1
- [kotlin系列] (s2_2)属性、字段、接口、可见性修饰
- Kotlin 学习之属性和字段
- Kotlin基础教程-属性和字段
- Kotlin-2.2-属性和字段
- Kotlin 字段和属性
- Kotlin 第七章:属性和字段
- 深入Kotlin - 专项 - Lambda表达式
- Kotlin学习(四)—— 类和对象,继承,覆盖,抽象类,属性和字段,接口,可见性修饰符,扩展
- Kotlin学习(三): 属性和字段
- Kotlin 从学习到 Android 第七章 属性和字段
- Kotlin汇总2-类构造,属性,字段
- 学习kotlin第七天_类与继承、属性与字段
- Kotlin-属性和字段
- Kotlin学习(四)—— 类和对象,继承,覆盖,抽象类,属性和字段,接口,可见性修饰符,扩展
- Kotlin-09.类属性和字段(Properties/Fields)
- 【Kotlin从入门到深坑】之类的属性和字段
- 深入理解c#的字段与属性
- 【Kotlin从入门到深坑】之类的属性和字段
- 深入理解Java中的字段与属性的区别