了解 Kotlin 中的字段和属性

10 篇文章 0 订阅
7 篇文章 0 订阅

当你声明一个属性时,Kotlin 如何为你隐式实现 field、getter 和 setter 函数?

Kotlin 中的属性和字段术语有时有点令人困惑,因为从技术上讲,Kotlin 没有字段。你不能声明一个字段。一切都是属性!

但是,为了避免混淆,我更喜欢根据以下内容分别定义字段和属性:

  • 字段是类的私有成员变量。内存已分配。
  • 属性是公共或受保护的 getter 或 setter 函数,允许您访问私有字段。

我喜欢这样定义,因为它有助于我的理解,也让事情更容易解释。

隐式字段,隐式 Getter/Setter

让我们看看这个例子。name是一个属性。

class Person {
    var name = "Vincent"
}

当您像这样声明一个属性时,Kotlin 会为您隐式创建字段、getter 和 setter 函数。

在 Java 反编译的代码中,它看起来像这样:

public final class Person {
   @NotNull
   private String name = "Vincent";

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

   public final void setName(@NotNull String var1) {
      Intrinsics.checkNotNullParameter(var1, "<set-?>");
      this.name = var1;
   }
}

如您所见,private String name是字段(成员变量)。getName()并且setName()是属性 getter 和 setter 函数(也称为属性访问器)

隐式字段,显式 Getter/Setter

当然,你也可以显式定义属性的getter和setter函数,这样也会生成非常类似的反编译Java代码。

class Person {
    var name: String = "Vincent"
        get() { return field }
        set(value) { field = value }
}

field在这里隐式创建,也称为Backing Fields。为属性提供属性访问器(即get()和set())称为支持属性。

显式字段,显式getter/setter

您也可以显式定义字段。基本上一切都是明确的。

class Person {  
    private var _name:String = "Vincent"  
    var name: String  
        get() { return _name }  
        set(value) { _name = value }  
}

field这里是显式字段,而不是隐_name式字段。

私人设置还是备用属性?

现在,您希望该属性name在类外只读。因此,您可以使用private set.

例如:

class Person {  
    var name: String = "Vincent"  
        private set  
}

或者您也可以使用支持属性。删除set()并更改var为val。

class Person {  
    private var _name:String = "Vincent"  
    val name: String  
        get() { return _name }  
}

这两个代码都生成与以下相同的反编译Java代码。请注意,该setName()功能已删除。

public final class Person {  
   @NotNull  
   private String name = "Vincent";  

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

我个人更喜欢private set,因为它的代码较少。

滥用私有集

但是等等,没那么快。如果您转换以下支持属性怎么办

class MainViewModel: ViewModel() {
    private val _state: MutableState<Int?> = mutableStateOf(null)
    val state: State<Int?> = _state
    /*...*/
}

至private set

class MainViewModel: ViewModel() {
    var state: MutableState<Int?> = mutableStateOf(null)
        private set
}

这是滥用private set. 它真正的意思是你不能state在类外分配一个新变量MainViewModel。state变量本身仍然是可变的(这意味着您可以修改它的值)。

上面的支持属性仅揭露读取State,将其更改为private set击败其原始目的。因此,在这种情况下,您不使用private set。这适用于任何可变数据。

结论

我认为在这里了解字段和属性概念很重要。

当您声明一个属性时,它不会分配新内存,因为它只是一个 getter 或 setter 函数。但是,如果推断隐式字段实现(如上面的代码示例),则是的,它占用内存分配。

最后,不要将每个支持属性转换为private set。您不应该这样做,尤其是您的数据是可变的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值