了解 Kotlin 中的字段和属性

Posted 小陈乱敲代码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了了解 Kotlin 中的字段和属性相关的知识,希望对你有一定的参考价值。

当你声明一个属性时,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。您不应该这样做,尤其是您的数据是可变的。

以上是关于了解 Kotlin 中的字段和属性的主要内容,如果未能解决你的问题,请参考以下文章

kotlin 中的 Observable.combineLatest 类型推断

为啥 Kotlin 不能推断以下 lambda 参数(在 Java -> Kotlin 转换之后)?

Kotlin学习——属性和字段

在 Kotlin 中无法“findViewById”。收到错误“类型推断失败”

Android-Kotlin-when&类型推断

kotlin与java互操作中的冲突