Kotlin 定义类与field关键

在 Kotlin 中,类的属性与 field 关键字的使用是语法设计中的重要特性。以下是详细解析:


一、Kotlin 类的定义

Kotlin 通过 class 关键字定义类,属性默认自动生成 getter/setter

kotlin 复制代码
class Person {
    var name: String = "默认值" // 自动生成 getter 和 setter
    val age: Int = 0          // 只读属性,仅生成 getter
}

二、field 关键字的作用

field 是 Kotlin 中用于访问属性‌幕后字段 ‌(backing field)的关键字,仅在属性的 get()set() 自定义逻辑中使用。

1. ‌**隐式使用 field**‌

默认情况下,Kotlin 会自动为属性生成幕后字段:

csharp 复制代码
var counter = 0
    // 等价于以下隐式代码:
    // get() = field
    // set(value) { field = value }

2. ‌**显式使用 field**‌

当自定义 get()set() 时,必须通过 field 访问实际存储值:

javascript 复制代码
var name: String = ""
    get() = field.uppercase()  // 返回大写值,但不修改存储值
    set(value) {
        field = value.trim()   // 赋值前去除首尾空格
    }

三、使用 field 的注意事项

1. ‌避免递归调用

直接使用属性名会触发 getter/setter,导致递归:

javascript 复制代码
// ❌ 错误示例:导致栈溢出
var counter = 0
    set(value) {
        if (value >= 0) this.counter = value // 递归调用 set()
    }

// ✅ 正确写法:使用 field
var counter = 0
    set(value) {
        if (value >= 0) field = value
    }

2. ‌仅限在 get()/set() 中使用

field 不可在类其他方法中直接访问:

kotlin 复制代码
class Demo {
    var data = 0
    
    fun update() {
        field = 10 // ❌ 编译错误:field 只能在 getter/setter 中使用
    }
}

四、无幕后字段的场景

如果属性不依赖幕后字段存储数据(例如通过计算获得值),则无需使用 field

kotlin 复制代码
val isAdult: Boolean
    get() = age >= 18  // 直接依赖其他属性,无需 field
    
    
 
// 计算属性  下面这样写 get函数覆盖了 field 内容本身,相当于field失效了,无用了,以后用不到了
var number2 : Int = 0
    get() = (1..1000).shuffled().first() // 从1到1000取出随机值 返回给 getNumber2()函数
/*
    背后隐式代码:
    为什么没有看到 number2 属性定义?
    答:因为属于 计算属性 的功能,根本在getNumber2函数里面,就没有用到 number2属性,所以 number2属性 失效了,无用了,以后用不到了

     public int getNumber2() {
        return (1..1000).shuffled().first()java的随机逻辑 复杂 ;
   }
 */

五、与 Java 的对比

特性 Java Kotlin
字段定义 显式声明为 private 字段 自动生成幕后字段,通过 field 访问
访问控制 手动实现 getter/setter 默认自动生成,可自定义逻辑
属性访问 直接访问字段或调用方法 统一通过属性名访问,隐藏底层实现

六、完整示例

ini 复制代码
class KtBase69 {

var name = "Derry"
    get() = field
    set(value) {
        field = value
    }
/* 背后做的事情:

   @NotNull
   private String name = "Lili";

   public void setName( @NotNull String name) {
        this.name = name;
   }

   @NotNull
   public String getName() {
        return this.name;
   }

 */

var value = "ABCDEFG"
    // 下面的隐式代码,不写也有,就是下面这个样子
    get() = field
    set(value) {
        field = value
    }

var info = "abcdefg ok is success"
    get() = field.capitalize() // 把首字母修改成大写
    set(value) {
        field = "**【$value】**"
    }
    

/* 背后做的事情:
    @NotNull
    private String info = "abcdefg ok is success";

    public void setInfo( @NotNull String info) {
        this.info = "**【" + info + "】**";
    }

    @NotNull
    public String getInfo() {
        return StringKt.capitalize(this.info)
    }

 */


}

class User {

    var email: String = ""
        set(value) {
            field = if (value.contains("@")) value else "invalid"
        }

    val info: String
        get() = "Email: $email"
}

//Kotlin 定义类与field关键
fun main(){

    // 背后隐式代码:new KtBase69().setName("wangwu");
    val ktBase69 = KtBase69()
    ktBase69.name = "wangwu"
    
    println(ktBase69.name)
    println("value:${ktBase69.value}")
    println("info: ${ktBase69.info}")

    val user = User()
    user.email = "test"  // 自动调用 setter,赋值 "invalid"
    println(user.info)
}

七、总结

  • ‌**field 的作用**‌:在自定义 get()/set() 中访问属性的实际存储值。
  • 使用场景‌:需要控制属性读写逻辑时(如数据校验、格式化)。
  • 避免错误 ‌:在自定义访问器中,始终用 field 替代属性名以避免递归。
相关推荐
马 孔 多 在下雨1 天前
安卓旋转屏幕后如何防止数据丢失-ViewModel入门
android
Just_Paranoid1 天前
【Settings】恢复出厂设置密码校验
android·python·settings·sha256·hmac-sha256
肥肥呀呀呀1 天前
flutter配置Android gradle kts 8.0 的打包名称
android·flutter
平生不喜凡桃李1 天前
C++ 异常
android·java·c++
Propeller1 天前
【Android】View 交互的事件处理机制
android·java
吴Wu涛涛涛涛涛Tao1 天前
Flutter 实现「可拖拽评论面板 + 回复输入框 + @高亮」的完整方案
android·flutter·ios
雨声不在1 天前
使用android studio分析cpu开销
android·ide·android studio
程序leo源2 天前
Linux_基础指令(二)
android·linux·运维·服务器·青少年编程
雨白2 天前
Android 两种拖拽 API 详解:ViewDragHelper 和 OnDragListener 的原理与区别
android