Kotlin 学习之属性和字段
2017-09-08 12:53
387 查看
属性和字段
属性声明
在 Kotlin 中类可以有属性,我们可以使用var关键字声明可变属性,或者用
val关键字声明只读属性。
class Address { var name: String = ... var street: String = ... var city: String = ... var state: String? = ... var zip: String = ... }
我们可以像使用 java 中的字段那样,通过名字直接使用一个属性:
fun copyAddress(address: Address): Address { val result = Address() // 在 kotlin 中没有 new 关键字 result.name = address.name // accessors are called result.street = address.street // ... return result }
Getters 和 Setters
声明一个属性的完整语法如下:var <propertyName>[: <PropertyType>] [= <property_initializer>] [<getter>] [<setter>]
语法中的初始化语句,
getter和
setter都是可选的。如果属性类型可以从初始化语句或者
getter的返回类型中推断出来,那么他的类型也是忽略的。
例子:
var allByDefault: Int? // 错误: 需要一个初始化语句, 默认实现了 getter和 setter 方法 var initialized = 1 类型为 Int, 默认实现了 getter 和 setter
只读属性的声明语法和可变属性的声明语法相比有两点不同: 它以
val而不是
var开头,不允许
setter函数:
val simple: Int? // has type Int, default getter, must be initialized in constructor val inferredType = 1 // has type Int and a default getter
我们可以像写普通函数那样在属性声明中自定义的访问器,下面是一个自定义的
getter的例子:
val isEmpty: Boolean get() = this.size == 0
下面是一个自定义的setter:
var stringRepresentation: String get() = this.toString() set(value) { setDataFromString(value) // parses the string and assigns values to other properties }
为了方便起见,
setter方法的参数名是
value,你也可以自己任选一个自己喜欢的名称。
从Kotlin 1.1开始,如果可以从getter方法推断出类型则可以省略之:
val isEmpty get() = this.size == 0 // has type Boolean
如果你需要改变一个访问器的可见性或者给它添加注解,但又不想改变默认的实现,那么你可以定义一个不带函数体的访问器:
var setterVisibility: String = "abc" private set // the setter is private and has the default implementation var setterWithAnnotation: Any? = null @Inject set // annotate the setter with Inject
备用字段
在 kotlin 中类不可以有字段。然而当使用自定义的访问器时有时候需要备用字段。出于这些原因 kotlin 使用field关键词提供了自动备用字段:
var counter = 0 // the initializer value is written directly to the backing field set(value) { if (value >= 0) field = value }
field 关键词只能用于属性的访问器,编译器会检查访问器的代码, 如果使用了备用字段(或者访问器是默认的实现逻辑),就会自动生成备用字段,否则就不会。
比如下面的例子中就不会有备用字段:
val isEmpty: Boolean get() = this.size == 0
初次看到备用字段的时候上面的代码你可能会这么想:
var counter = 0 set(value) { if (value >= 0) this.counter = value }
用
this.counter代替
field是不是等效的
但是结果却是发生了死循环。
分析
this.counter = value这样的赋值语句在kotlin中实际就是调用了属性的
set(value)方法,这样其实就是形成了无休止的递归。
备用属性
如果你想要做一些事情但不适合这种 “隐含备用字段” 方案,你可以试着用备用属性的方式:private var _table: Map<String, Int>? = null public val table: Map<String, Int> get() { if (_table == null) { _table = HashMap() // Type parameters are inferred } return _table ?: throw AssertionError("Set to null by another thread") }
综合来讲,这些和 java 很相似,可以避免函数访问私有属性而破坏它的结构。
编译时常量
那些在编译时就能知道具体值的属性可以使用 const 修饰符标记为 编译时常量。这种属性需要同时满足以下条件:在top-level声明的 或者 是一个 object 的成员
以 String 或基本类型进行初始化
没有自定义getter
这种属性可以被当做注解使用:
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated" @Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { ... }
延迟初始化属性
通常,那些被定义为拥有非空类型的属性,都需要在构造器中初始化。但有时候这并没有那么方便。例如在单元测试中,属性应该通过依赖注入进行初始化, 或者通过一个
setup方法进行初始化。
在这种条件下,你不能在构造器中提供一个非空的初始化语句,但是你仍然希望在访问这个属性的时候,避免非空检查。
为了处理这种情况,你可以为这个属性加上
lateinit修饰符
public class MyTest { lateinit var subject: TestSubject @SetUp fun setup() { subject = TestSubject() } @Test fun test() { subject.method() // dereference directly } }
这个修饰符只能够被用在类的
var类型的可变属性定义中,不能用在构造方法中。
并且属性不能有自定义的
getter和
setter访问器。
这个属性的类型必须是非空的,同样也不能为一个基本类型。
在一个
lateinit的属性初始化前访问他,会导致一个特定异常,告诉你访问的时候值还没有初始化.
复写属性
参看 复写属性代理属性
最常见的属性就是从备用属性中读(或者写)。另一方面,自定义的getter和
setter可以实现属性的任何操作。有些像懒值( lazy values ),根据给定的关键字从map 中读出,读取数据库,通知一个监听者等等,像这些介于
getter
setter模式之间的操作可以通过代理属性作为库来实现。更多请参看代理属性.
相关文章推荐
- 学习kotlin第七天_类与继承、属性与字段
- Kotlin学习(四)—— 类和对象,继承,覆盖,抽象类,属性和字段,接口,可见性修饰符,扩展
- Kotlin学习(三): 属性和字段
- Kotlin 学习笔记(七)—— Kotlin类与对象之属性与字段
- Kotlin学习(四)—— 类和对象,继承,覆盖,抽象类,属性和字段,接口,可见性修饰符,扩展
- Kotlin 官方学习教程之属性和字段
- Kotlin学习(9):属性和字段
- Kotlin 从学习到 Android 第七章 属性和字段
- MyBatis学习总结(四)——解决字段名与实体类属性名不相同的冲突
- SQL 数据库 学习 007 通过一个示例简单介绍什么是字段、属性、列、元组、记录、表、主键、外键 (上)
- MyBatis学习总结(4)——解决字段名与实体类属性名不相同的冲突
- MyBatis学习总结(四)——解决字段名与实体类属性名不相同的冲突
- Kotlin汇总2-类构造,属性,字段
- MyBatis学习总结(四)——解决字段名与实体类属性名不相同的冲突
- c#学习摘录:类\继承\接口\字段、方法、属性\浅深复制(1)
- MyBatis学习总结(4)——解决字段名与实体类属性名不相同的冲突
- mybatis学习笔记(三) --- 解决字段名与实体类属性名不相同的冲突
- 请问大家 刚开始学习sql 请问我已经建立了几个字段,怎么用sql修改 这几个字段的属性呢?
- 学习笔记之--属性、字段、变量
- MyBatis学习总结(四)——解决字段名与实体类属性名不相同的冲突