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() // there's no 'new' keyword in Kotlin |
result.name = address.name // accessors are called |
result.street = address.street |
// ... |
return result |
} |
var <propertyName>[: <PropertyType>] [= <property_initializer>] |
[<getter>] |
[<setter>] |
初始化程序,getter
和setter
是可选的。 如果可以从初始化程序(或从getter
返回类型,如下所示)推断属性类型,则属性类型是可选的。
例子:
var allByDefault: Int? // error: explicit initializer required, default getter and setter implied |
var initialized = 1 // has type Int, default getter and 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 |
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提供了可以使用字段标识符访问的自动备份字段:
var counter = 0 // the initializer value is written directly to the backing field |
set(value) { |
if (value >= 0) field = value |
} |
field
标识符只能在属性的访问器中使用。
如果属性使用至少一个访问器的默认实现,或者自定义访问器通过field
标识符引用它,则将为属性生成后备字段。
例如,在以下情况下,将不会有后备字段:
val isEmpty: Boolean |
get() = this.size == 0 |
如果想做一些不符合这个“隐性后备字段”方案的东西,总是可以回到拥有一个后备属性:
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中的一样,因为使用默认getter
和setter
的私有属性的访问被优化,因此不会引入函数调用开销。
编译时常数
在编译时已知其值的属性可以使用const
修饰符标记为编译时常数。 这些属性需要满足以下要求:
getter
这些属性可以在注释中使用:
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated" |
@Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { ... } |
通常,声明为非空类型的属性必须在构造函数中进行初始化。 然而,这通常不方便。 例如,可以通过依赖注入或单元测试的设置方法初始化属性。 在这种情况下,不能在构造函数中提供非空的初始值设置,但是仍然希望在引用类的正文中的属性时避免空检查。
要处理这种情况,可以使用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
可以实现属性的任何行为。属性如何运作有一些共同的模式。 几个例子:懒值,通过给定的键读取映射,访问数据库,通知访问者等。