1、 声明属性
在 Kotlin 中 属性分为 可变属性 和 只读属性:
- var 可变
- val 只读
示例;
class Mike {
val name: String = "Mike"
var age: Int = 25
}
2、完整的属性声明
声明一个属性的完整语法为:
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
其中 初始器(initializer)
、getter
和 setter
都是可选的。
我们可以自定义访问器,具体场景为新建一个可以判断是否为正方形的矩形类:
class Rectangle(val height: Int, val width: Int) {
val isSquare: Boolean
get() { // 属性的获取函数声明
return height == width
}
}
一个自定义 setter 的例子;
var stringRepresentation: String
get() = this.toString()
set(value) {
setDataFromString(value) // 解析字符串并赋值给其他属性
}
如果要 改变一个访问器的可见性或者对其注解
,那么不需要改变其默认实现,只需要定义该属性的访问器而不是其实现,以下为例:
var setterVisibility: String = "abc"
private set // 此 setter 是私有的并且有默认实现
var setterWithAnnotation: Any? = null
@Inject set // 用 Inject 注解此 setter
3、Backing Field
自己对 Kotlin 中相关 Backing Field
的内容比较疑惑,单独写一篇博客来记录,具体详见Kotlin 全面学习之路 (九) – 对 Kotlin 中 Backing Field 的理解 。
4、后端属性(Backing Property)
如果你希望实现的功能无法通过这种 “隐含的后端域变量” 方案来解决, 你可以使用 后端属性(backing property) 作为替代方案:
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")
}
不管从哪方面看, 这种方案都与 Java 中完全相同, 因为后端私有属性的取值方法与设值方法都使用默认实现, 我们对这个属性的访问将被编译器优化, 变为直接读写后端域变量, 因此不会发生不必要的函数调用, 导致性能损失.
5、编译期常量
在阐述 编译期常量前,我们需要先理解 运行时常量 和 编译期常量:
- 运行时常量是编译时并不知道其值,真正运行的时候才获取
- 编译期常量是编译时候就知道其值的常量
- kotlin中 val 并不是编译期常量,可通过反射的方式修改值,要将其转成编译期常量需要加上 const 关键词,可提高运行效率。
已知值的属性可以使用 const 修饰符标记为 编译期常量,不过这些属性需要满足以下要求:
- 位于顶层或者是
object
的一个成员。验证这一条件十分容易,在一个类的属性前添加 const 修饰符,此时你会看到错误信息:const 'val' are only allowed on top level or in object
。 - 用 String 或原生类型初始化 。同样可以在代码中进行验证 。
- 没有自定义 getter 。同样可以在代码中进行验证 。
这些属性可以用在注解中:
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is depr
ecated"
@Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { …… }
6、延迟初始化属性与变量
一般的,属性声明为 非空类型
必须在构造函数中 初始化
。,但是有些情况下,我们不能在构造函数内提供一个非空初始化属性,比如需要一个类对象,但是此类对象需要通过一系列操作才可以得到,同时你还想在类体中引用该对象是避免空检查,那么此时延迟初始化属性就是必要的了。
为了实现延迟初始化属性,我们可以使用 lateinit 修饰符来标记该对象(属性)。
public class People{
lateinit var dog: Dog()
fun setDog(dog: Dog){
this.dog = dog
}
fun showDogInfo(){
//dog?.show()
//dog!!.show()
// 此时就不用做空检查,以上两行代码就没有必要了
dog.show()
}
}
在初始化前访问一个 lateinit 属性会抛出一个特定异常,该异常明确标识该属
性被访问及它没有初始化的事实。
7、覆盖属性
子类覆盖父类的相应属性使用 override
修饰符修饰该属性。
- var 属性可以覆盖 val 属性,反之不行
- 每个声明的属性可以由具有初始化器的属性或者具有 getter 方法的属性覆盖。
8、委托属性
自己对 Kotlin 中相关委托的内容比较疑惑,单独写一篇博客来记录,具体详见。