Kotlin开发笔记之委托属性与区间(译)

论坛 期权论坛     
niminba   2021-5-26 12:30   2669   0
<p><span style="color: #ff0000"><strong>前言</strong></span></p>
<p>本文主要给大家介绍了关于Kotlin委托属性与区间的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。</p>
<p><span style="color: #ff0000"><strong>委托属性</strong></span></p>
<p>有一些常见的属性类型,虽然我们可以在每次需要的时候手动实现它们, 但是如果能够为大家把他们只实现一次并放入一个库会更好。例如包括</p>
<ul>
  <li>延迟属性(lazy properties): 其值只在首次访问时计算,</li>
  <li>可观察属性(observable properties): 监听器会收到有关此属性变更的通知,</li>
  <li>把多个属性储存在一个映射(map)中,而不是每个存在单独的字段中。</li>
</ul>
<p>为了涵盖这些(以及其他)情况,Kotlin 支持 委托属性:</p>
<div class="blockcode">
<pre class="brush:java;">
class Example {
var p: String by Delegate()
}</pre>
</div>
<p>委托属性 是一种通过委托实现拥有 getter 和可选 setter 的 属性,并允许实现可复用的自定义属性。例如:</p>
<div class="blockcode">
<pre class="brush:java;">
class Example {
var p: String by Delegate()
}</pre>
</div>
<p>委托对象必须实现一个拥有 <code>getValue() </code>方法的操作符,以及 <code>setValue() </code>方法来实现读/写属性。些方法将会接受包含对象实例以及属性元数据作为额外参数。当一个类声明委托属性时,编译器生成的代码会和如下 Java 代码相似。</p>
<div class="blockcode">
<pre class="brush:java;">
public final class Example {
@NotNull
private final Delegate p$delegate = new Delegate();
// $FF: synthetic field
static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Reflection.getOrCreateKotlinClass(Example.class), "p", "getP()Ljava/lang/String;"))};
@NotNull
public final String getP() {
return this.p$delegate.getValue(this, $$delegatedProperties[0]);
}
public final void setP(@NotNull String var1) {
Intrinsics.checkParameterIsNotNull(var1, "&lt;set-&#63;&gt;");
this.p$delegate.setValue(this, $$delegatedProperties[0], var1);
}
}</pre>
</div>
<p>一些静态属性元数据被加入到类中,委托在类的构造函数中初始化,并在每次读写属性时调用。</p>
<p><span style="color: #ff0000"><strong>委托实例</strong></span></p>
<p>在上面的例子中,创建了一个新的委托实例来实现属性。这就要求委托的实现是有状态的,例如,当其内部缓存计算结果时:</p>
<div class="blockcode">
<pre class="brush:java;">
class StringDelegate {
private var cache: String&#63; = null
operator fun getValue(thisRef: Any&#63;, property: KProperty&lt;*&gt;): String {
var result = cache
if (result == null) {
result = someOperation()
cache = result
}
return result
}
}</pre>
</div>
<p>与此同时,当需要额外的参数时,需要建立新的委托实例,并将其传递到构造器中。</p>
<div class="blockcode">
<pre class="brush:java;">
class Example {
private val nameView by BindViewDelegate&lt;TextView&gt;(R.id.name)
}</pre>
</div>
<p>但也有一些情况是只需要一个委托实例来实现任何属性的:当委托是无状态,并且它所需要的唯一变量就是已经提供好的包含对象实例和委托名称时,可以通过将其声明为 object 来替代 class 实现一个单例委托。</p>
<p>举个例子,下面的单例委托从 Android Activity 中取回与给定 tag 相匹配的 Fragment。</p>
<div class="blockcode">
<pre class="brush:java;">
object FragmentDelegate {
operator fun getValue(thisRef: Activity, property: KProperty&lt;*&gt;): Fragment&#63; {
return thisRef.fragmentManager.findFragmentByTag(property.name)
}
}</pre>
</div>
<p>类似地,任何已有类都可以通过扩展变成委托。<code>getValue()</code> 和 <code>setValue() </code>也可以被声明成 扩展方法 来实现。Kotlin 已经提供了内置的扩展方法来允许将 Map and MutableMap 实例用作委托,属性名作为其中的键。 <br>
</p>
<p>如果你选择复用相同的局部委托实例来在一个类中实现多属性,你需要在构造函数中初始化实例。 <br>
</p>
<p><span style="color: #800000"><strong>注意:</strong></span>从 Kotlin 1.1 开始,也可以声明 方法局部变量声明为委托属性。在这种情况下,委托可以直到该变量在方法内部声明的时候才去初始化,而不必在构造函数中就执行初始化。</p>
<p><span style="color: #ff0000"><strong>泛型委托</strong></span></p>
<p>委托方法也可以被声明成泛型的,这样一来不同类型的属性就可以复用同一个委托类了。</p>
<div class="blockcode">
<pre class="brush:java;">
private var maxDelay: Long by SharedPreferencesDelegate&lt;Long&gt;()</pre>
</div>
<p>然而,如果像上例那样对基本类型使用泛型委托的话,即便声明的基本类型非空,也会在每次读写属性的时候触发装箱和拆箱的操作。</p>
<p>说明:对于非空基本类型的委托属性来说,最好使用给定类型的特定委托
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1060120
帖子:212021
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP