一、声明属性
- )Kotlin 类中的属性同变量一样既可以用关键字 var 声明为可变的,也可以用关键字 val 声明为不可变的。
如下:
open class Person {
val hello = "hello,everyone!"
var userName = "jf"
var userAge = 26
}
- )类的对象调用一个属性,使用.操作符加属性名称即可。
val person = Person()
person.userName
- )类的属性默认是public的,默认情况下public可省略
val hello = "hello,everyone!"
其实是
public val hello = "hello,everyone!" //public默认省略
二、Getters 与 Setters
声明一个属性的完整语法如下:
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
val <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
其初始器(initializer)、getter 和 setter 都是可选的。属性类型如果可以从初始器 (或者从其 getter 返回值,如下文所示)中推断出来,也可以省略。
这里我们着重看一下getter 和 setter:
getter 和 setter是什么,getter 和 setter是属性访问器(getter是读访问器,setter是写访问器,因为val是只读变量,所以只有getter访问器),是属性声明的一部分,声明一个属性会默认提供getter和setter,并且我们也可以自定义getter和setter。
getter、setter可以理解为Java中的set()和get()方法。
如下:
public class Person {
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
我们访问一个属性,通过.运算符,它其实就是执行了该属性的getter访问器,如下:我们重写getter访问器,返回一个新的值
open class Person {
var userName = "jf"
get() = "真正的用户名称"
var userAge = 26
}
val person = Person()
Log.e("----",person.userName)
上述代码的运行结果是:
真正的用户名称
类似的,我们给一个属性赋值其实是执行了该属性的setter访问器
如下:
open class Person {
var userName = "jf"
set(value) {
Log.e("执行了setter访问器" , value)
}
var userAge = 26
}
val person = Person()
person.userName = "新的用户名"
Log.e("新的用户名",person.userName)
上述代码的运行结果是:
执行了setter访问器: 新的用户名
新的用户名: jf
可以看到上述执行了setter访问器,但我们自定义时没有真正的赋值,所以userName的值还是初始值。
那我们如何自定义setter并完成重新赋值呢?
Kotlin会给setter、getter提供幕后字段,用关键字field表示,幕后字段只能在getter 和setter中访问。
默认的setter访问器其实如下,如果我们自定义的setter访问器如果跟下面一样,编译器就会提示我们去掉
set(value) {
field = value
}
同样默认的getter访问器如下:
get() = field
所以我们可以通过自定义setter访问器做更多的事,比如在原来的赋值上做数据转换之类的:
open class Person {
var userName = "jf"
set(value) {
field = value.uppercase()
}
}
val person = Person()
person.userName = "hello world"
Log.e("新的用户名",person.userName)
上述代码的运行结果是:
新的用户名: HELLO WORLD
到此,我们已经会使用幕后字段field了,我们可以进一步理解幕后字段。我们还是以Person类为例,Person类里定义了一个属性userName ,如下:
open class Person {
var userName = "jf"
}
如果我们将该类转换成Java会是怎么样的呢?如下:
public class Person {
private String userName= "jf";
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
这已经很清楚了,我们可以这么理解:转换后Java代码中userName其实就是幕后字段,getUserName和setUserName其实就是getter和setter访问器,我们在kotlin中代码中初始化userName就是给Java 中的userName这个幕后字段赋值,在kotlin中代码中访问和赋值userName其实就是调用的Java 中的userName这个幕后字段的getUserName和setUserName方法。
三、幕后属性
一个属性对内为可读可写,对外为只读
如下:
open class Person {
private var _userAge : Int = 18
val userAge : Int
get() = _userAge
}
_userAge属性是private修饰的,因此只有内部可以访问外部不能访问,外部访问userAge属性其实是访问了_userAge属性的值,这种情况下_userAge就是幕后属性。
四、Const 和 Lateinit
Const 声明编译时常数
Lateinit 声明后期初始化属性
我们前面已经讲过了,这里不再重复。