我现在正在学习 Kotlin。就上下文而言,我是一名 Java 开发人员已有 10 年以上了。
我偶然发现了支持属性的概念。据我了解,要解决的问题是:我在一个类中有一个属性。我希望此属性是可变的并且仅在包含的类中可见,因此我将其声明为private var
. 该属性只能在包含的类中修改,但在类外应该是可读的。因此,Kotlin 文档提出了这样的建议:
private var _word = "test"
val word: String
get() = _word
Run Code Online (Sandbox Code Playgroud)
这可以工作并满足上述要求,但是对于 Java 开发人员来说这看起来有点奇怪。在Java中,我们只需要1个字段(Java中没有属性这样的东西):
private String word = "test";
public String getWord() {
return word;
}
Run Code Online (Sandbox Code Playgroud)
AFAIK,同样的结果。
今天我了解到,在 Kotlin 中,我可以将 setter 设为私有。那么这个 Kotlin 代码怎么样:
var word = "test"
private set
Run Code Online (Sandbox Code Playgroud)
满足所有要求,代码更加简洁。
我错过了什么吗?为什么我需要支持财产?
(这个答案从一些有关 Kotlin 属性的一般信息开始,因为人们似乎对它们普遍感到困惑。)
\nKotlin 和 Java 之间的主要概念差异在于,在 Java 中,基本的东西是字段,而在 Kotlin 中,基本的东西是访问器方法。
\n因此,在 Java 中,您定义一个字段。\xe2\x80\x82 然后,如果需要,您可以为其定义显式 getter 和/或 setter 方法。\xe2\x80\x82该语言没有 \xe2\x80 的概念\x98property\xe2\x80\x99,也没有定义访问器和字段之间的任何显式连接;但是访问器方法名称(最初源自JavaBeans )有一个几乎每个人都遵循的长期约定。
\n这很清楚,但很啰嗦。\xe2\x80\x82并且因为它只是一个约定,所以该语言不会强制您将字段与访问器相匹配:您可以拥有不同类型的访问器、没有 getter 的 setter 和反之亦然,甚至没有字段的访问器。\xe2\x80\x82(其中一些东西是可取的,但其他东西更可能导致错误和混乱!)
\n然而,Kotlin 认为访问器才是重要的。\xe2\x80\x82(这是一个一般原则的示例,您应该针对接口进行编程,而不关心它是如何实现的。)\xe2 \x80\x82实际上,属性 就是它的访问器。\xe2\x80\x82只要你有 getter 方法,那么你就可以获得属性的值;只要你有一个setter方法,那么你也可以设置它。
\n因为 getter 和 setter 通常都很琐碎,所以 Kotlin 会隐式定义它们,除非您另有说明。\xe2\x80\x82因此,当您编写时:
\nval myProperty = 1\n
Run Code Online (Sandbox Code Playgroud)\n然后 Kotlin 创建:
\nmyProperty
,其类型推断为Int
,并初始化为值 1。getMyProperty()
,具有公共范围(默认情况下),返回一个Int
.这正是您在 Java 中所做的,只是更简洁。
\n不同的是,每当您引用该属性时,您都会调用访问器方法,而不是直接访问该字段。\xe2\x80\x82(这就是为什么它被称为支持字段\ xe2\x80\x94 其唯一目的是供访问器使用。)
\n当然,除非覆盖访问器,否则效果是相同的。\xe2\x80\x82例如:
\nval myProperty = 1\n get() {\n LOG.info("Getting value of myProperty = $field")\n return field\n }\n
Run Code Online (Sandbox Code Playgroud)\n(field
是 getter 和 setter 中的特殊关键字,指的是它们的支持字段。)
和之前一样,这会生成一个字段和一个 getter 方法;但 getter 方法是在代码中指定的,而不是自动生成的。
\n(我没有提到可变属性或 setter,但原理是相同的:如果属性是 a var
,那么您也会获得自动生成或显式 setter 方法。\xe2\x80\x82Kotlin没有的一种 Java 可能性\不支持只写属性,其中某些作用域可以看到 setter 但看不到 getter。\xe2\x80\x82 但这些很少使用;您始终可以使用普通方法来设置它们,这可能更清楚。)
还有一种情况需要考虑。\xe2\x80\x82在 Java 中,getter 方法可以单独存在,无需相应的字段。\xe2\x80\x82(然后它必须从其他来源获取其值 \ xe2\x80\x94 可能通过对其他字段执行计算,或者从另一个对象获取它,甚至使用硬编码值。)
\n您可以在 Kotlin 中执行相同的操作,方法是覆盖 getter(和 setter,如果可变)并且不引用field
,例如:
val myProperty: Int\n get() = someOtherObject.someOtherProperty\n
Run Code Online (Sandbox Code Playgroud)\n在这种情况下,生成字段是没有意义的,因为它永远不会被使用!\xe2\x80\x82所以 Kotlin 识别这一点并只生成生成访问器方法。
\n它仍然是一个属性,因为它仍然有访问器方法,其余代码看不到任何区别。\xe2\x80\x82它是否有支持字段纯粹是一个实现细节。
\n这个问题询问的是 \xe2\x80\x98backing属性\xe2\x80\x99.\xe2\x80\x82官方文档使用该术语来表示一个单独的私有属性,其中 \xe2\x80\x98shadows\xe2\x80\x99现有的,如本问题所示。\xe2\x80\x82(感谢 cactustictacs 提供参考。)
\n在某些特定情况下,支持属性可能很有用。\xe2\x80\x82例如,假设您需要引用类中的特定类型,但仅公开公开超类型;私有财产可以是特定类型,然后公共财产可以是超类型。
\n然而,这并不需要简单地限制 setter 方法的可见性:正如问题所示,这可以明确地完成(例如通过添加private set
到属性定义中)。
(根据我的经验,很少需要支持属性。)
\n 归档时间: |
|
查看次数: |
2110 次 |
最近记录: |