1.field
field
关键字通常与属性的自定义 getter 和 setter 一起使用。当你需要为一个属性提供自定义的行为时,可以使用 field
来访问或设置该属性的实际存储值。
class Player {
var age: Int = 0
get() = field // 自定义 getter
set(value) { // 自定义 setter
if (value >= 0) {
field = value
} else {
println("年龄不能为负数")
}
}
}
fun main() {
val player = Player()
player.age = 30 // 正常设置
println(player.age) // 输出 30
player.age = -5 // 尝试设置无效的年龄
println(player.age) // 输出 30(因为设置失败,所以仍然是 30)
}
更复杂的自定义行为
class Person {
private var _age: Int = 0 // 私有字段
var age: Int
get() {
println("获取年龄: $_age")
return _age
}
set(value) {
if (value >= 0) {
println("设置年龄: $value")
_age = value
} else {
println("年龄不能为负数: $value")
}
}
}
fun main() {
val person = Person()
person.age = 30 // 输出: 设置年龄: 30
println(person.age) // 输出: 获取年龄: 30
// 30
person.age = -5 // 输出: 年龄不能为负数: -5
println(person.age) // 输出: 获取年龄: 30
// 30
}
- field 关键字:在自定义的 getter 和 setter 中,field 代表属性背后的实际存储字段。
- 自定义 getter 和 setter:允许你在读取和写入属性时执行额外的逻辑,如数据验证、日志记录等。
- 私有字段:为了更好地控制属性的访问,可以使用私有字段来存储实际值,并通过公开的属性提供访问接口。
2.计算属性
- 计算属性:这些属性没有后台字段来存储值,而是通过 getter 方法在每次访问时计算并返回值。
- 自定义 getter:你可以在类中定义一个没有显式初始化值的 val 属性,并为其提供一个自定义的 getter 方法。
class Rectangle(val width: Int, val height: Int) {
// 计算属性
val area: Int
get() = width * height // 自定义 getter
}
fun main() {
val rectangle = Rectangle(10, 5)
println("宽度: ${rectangle.width}") // 输出 宽度: 10
println("高度: ${rectangle.height}") // 输出 高度: 5
println("面积: ${rectangle.area}") // 输出 面积: 50
}
3.主构造函数
在People类的定义头中定义一个主构造函数,使用临时变量为Player的各个属性提供初始值,在Kotlin中,为了便于识别临时变量通常都会以下划线开头的名字命名。
class People(
_name:String,
_age:Int,
_isNormal:Boolean
) {
var name = _name
get() = field.capitalize()
set(value){
field = value.trim()
}
var age = _age
get() = field
set(value){
field = value.absoluteValue
}
var isNormal = _isNormal
}
fun main(){
val people = People("Jack", 20, true)
println(people.name)
println(people.age)
println(people.isNormal)
}
4.次构造函数
除了主构造函数还有次构造函数,我们可以定义多个次构造函数来配置不同的参数组合。
class People0(
_name:String,
var age:Int,
var isNormal:Boolean
) {
var name = _name
get() = field.capitalize()
set(value){
field = value.trim()
}
constructor(name : String) : this(name , age = 10, isNormal = false) {
this.name = name.capitalize()
}
}
fun main(){
val people0 = People0("rose")
println(people0.name) // Rose
println(people0.age) // 0
println(people0.isNormal) // false
}
5.默认参数
定义构造函数时,可以给构造函数指定默认值,如果用户调用时不提供值参,就是用这个默认值。
class People1(
_name:String,
var age:Int = 99,
var isNormal:Boolean = false
) {
var name = _name
get() = field.capitalize()
set(value){
field = value.trim()
}
constructor(name : String) : this(name , age = 10, isNormal = false) {
this.name = name.capitalize()
}
}
fun main(){
val people1 = People1(_name = "jim")
println(people1.name) // Jim
println(people1.age) // 99
println(people1.isNormal) // false
}
6.初始化块
初始化块可以设置变量或值,以及执行有效性检查,如检查传给某构造函数的值是否有效,初始化块代码会在构造类实例时执行。
class People1(
_name:String,
var age:Int = 99,
var isNormal:Boolean = false
) {
var name = _name
get() = field.capitalize()
set(value){
field = value.trim()
}
constructor(name : String) : this(name , age = 10, isNormal = false) {
this.name = name.capitalize()
}
init {
require(age > 0){"年龄设置不能小于0"}
}
}
fun main(){
val people1 = People1(_name = "jim",-1, false)
println(people1.name) // Jim
println(people1.age) // 198
println(people1.isNormal) // false
}
7.初始化顺序
- 主构造函数里声明的属性
- 类级别的属性赋值
- init初始化块里的属性赋值和函数调用
- 次构造函数里的属性赋值和函数调用
class Student(
_name : String,
val age : Int
){
var name = _name
var score = 10
var hobby = "music"
val subject : String
init {
println("initializing student...")
subject = "Chinese"
}
constructor(_name:String) : this(_name,10){
score = 100
}
}
fun main(){
val student = Student("Jack")
}
public Student(@NotNull String _name) {
Intrinsics.checkNotNullParameter(_name, "_name");
this(_name, 10);
this.score = 100;
}
public Student(@NotNull String _name, int age) {
Intrinsics.checkNotNullParameter(_name, "_name");
super();
this.age = age;
this.name = _name;
this.score = 10;
this.hobby = "music";
String var3 = "initializing student...";
System.out.println(var3);
this.subject = "Chinese";
}
7.延迟初始化lateinit
- 使用lateinit关键字相当于做了一个约定:在用它之前负责初始化
- 只要无法确认lateinit变量是否完成初始化,可以执行isInitialized检查
class Player4 {
lateinit var equipment : String
fun ready(){
equipment = "AK-47"
}
fun battle(){
if (::equipment.isInitialized){
println(equipment)
}else{
println("没有武器")
}
}
}
fun main(){
val player4 = Player4()
// player4.ready()
player4.battle()
}
8.惰性初始化
延迟初始化并不是初始化的唯一方式,你也可以暂时不初始化某个变量,知道首次使用它,叫做惰性初始化。
class Player5(_name :String) {
var name = _name
val config by lazy {
loadConfig()
}
private fun loadConfig():String{
println("loading...")
return "xxx"
}
}
fun main() {
val p = Player5("kim")
Thread.sleep(4000)
// 4s后才会打印
println(p.config)
}