kotlin的class里边的property概念跟java的class里边的feild或者property概念还不太一样。
kotlin的代码最终都要转化成Java代码,kotlin的类里边的属性不一定都要对应一个java类里边的属性,必须满足一以下条件之一:
1. 使用至少一个缺省accessor(getter or setter)
2. 如果使用了定制accessor, 在accessor方法内,有通过feild去访问类的成员变量
(Kotlin will generate a backing field for a property if we use at least one default accessor or we reference the field identifier inside a custom accessor. Default accessors are those that are generated with val or var keywords.)
比如下边的类子:
data class HttpResponse(val body: String, var httpHeader: Map<String, String>) {
val hasBody: Boolean
get() = body.isNotBlank()
var statusCode: Int = 100
set(value) {
if (value in 100..500)
field = value
}
}
body, httpHeader, statusCode都有backing field, 所谓的backing feild,就是kotlin代码转成java代码时,有对应的java class field, 而hasBody就没有backing field, 因为他不符合上边说的任何一个条件。转化成java代码如下:
public final class HttpResponse {
private int statusCode;
private final java.lang.String body;
private java.util.Map<java.lang.String, java.lang.String> headers;
// truncated
另外,要注意的是,上边的例子中,如果将val hasBody改成var hasBody, 则有backing field, 而且必须初始化该变量,比如像下边这样,否则编译错误:
val hasBody: Boolean = true
get() = body.isNotBlank()
最后,为什么在kotlin中使用backing field,比如如果上边代码改成这样:
data class HttpResponse(val body: String, var httpHeader: Map<String, String>) {
...
var statusCode: Int = 100
set(value) {
if (value in 100..500)
statusCode = value <<<<<<<<<<<,
}
}
那将陷入递归死循环,因为在kotlin中,对属性赋值操作相当于调用setter方法。