了解 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 转换之后)?