




下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】如何在Kotlin中使用扩展函数和扩展属性
如何在Kotlin中使用扩展函数和扩展属性?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面在下将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Kotlin能够扩展一个类的新功能而无需继承该类或者使用像装饰者这样的设计模式。这通过叫做扩展的特殊声明完成。例如,你可以为一个你不能修改的、来自第三方库中的类编写一个新的函数。这个新增的函数就像那个原始类本来就有的函数一样,可以用普通的方法调用。这种机制称为扩展函数。public
class
Utils
{
public
static
float
dp2px(int
dpValue)
{
return
(0.5f
+
dpValue
*
Resources.getSystem().getDisplayMetrics().density);
}
}在代码中直接调用Utils.dp2px(100)来使用,val
dp2px
=
Utils.dp2px(100)如果用kotlin扩展函数的方式来实现,会是怎么调用呢?val
dp2px
=
100.dp2px()是不是很惊讶,100作为一个Int,竟然直接调用了一个dp2px方法,如果你去源码里找找,其实是没有个方法的。我们没有动源码,而是使用拓展函数的方式为Int增加了一个方法。fun
Int.dp2px():
Float
{
return
(0.5f
+
this
*
Resources.getSystem().displayMetrics.density)
}扩展函数我们再来举个?,有一个Person类如下class
Person(val
name:
String)
{
fun
eat()
{
Log.i(name,
"I'm
going
to
eat")
}
fun
sleep()
{
Log.i(name,
"I'm
going
to
sleep")
}
}它有两个方法,一个是eat、一个是sleep,调用的话就分别打印相应的Log。我们现在不想动Person类,但是又想给他增加一个新的方法,怎么做呢。我们可以新建一个文件PersonExtensions.kt,再通过一下代码实现,就可以为Person类新增一个drink方法啦。fun
Person.drink()
{
Log.i("Person",
"${}:
I'm
going
to
drink")
}声明一个扩展函数,我们需要用一个接收者类型也就是被扩展的类型来作为他的前缀。上面我们就是以Person作为一个扩展函数的接收类型,为其拓展来drink方法。我们在其方法中调用了this,这个this指的就是调用这个拓展方法的当前Person对象。扩展函数调用的话也和普通的方法相同。但是你会发现IDE显示的方法颜色有点不一样。由此也可以看出普通的方法和我们的拓展函数是不同的。下面我们来看看扩展函数的实际实现。在AndroidStudio中,我们可以查看kotlin文件的字节码,然后再Decompile为Java代码。上面我们为Person扩展函数转为Java代码后如下。@Metadata(
mv
=
{1,
1,
15},
bv
=
{1,
0,
3},
k
=
2,
d1
=
{"\u0000\f\n\u0000\n\u0002\u0010\u0002\n\u0002\u0018\u0002\n\u0000\u001a\n\u0010\u0000\u001a\u00020\u0001*\u00020\u0002¨\u0006\u0003"},
d2
=
{"cook",
"",
"Lcom/chaochaowu/kotlinextension/Person;",
"app_debug"}
)
public
final
class
PersonExtensionsKt
{
public
static
final
void
cook(@NotNull
Person
$this$cook)
{
Intrinsics.checkParameterIsNotNull($this$cook,
"$this$cook");
Log.i("Person",
$this$cook.getName()
+
":
I'm
going
to
cook");
}
}妹想到啊,它原来是一个staticfinal声明的静态方法,它的入参是一个Person类型,也就是我们之前的接收类型。那在Java代码中能不呢调用呢?PersonExtensionsKt.cook(new
Person("Bob"));竟然也没有报错!由此可见,所谓扩展函数并不是真正的在类中增加了一个方法,而是通过外部文件的静态方法来实现,其实就是和Utils类一个道理。因为将一个Person作为入参传入了方法中,所以我们也就可以在方法内对这个Person对象进行操作,这也就是在扩展方法中我们可以使用this来访问Person属性的原因。再来看一个特殊的例子。val
s:
String?
=
null
s.isNullOrEmpty()上面的代码中,s的值为null,我们用null去调用了一个方法,这会不会报错呢?按照以前的经验,一个null去调用一个方法,必然会报空指针的异常,但是上面的代码却是不会崩的。为什么哩?其实isNullOrEmpty是CharSequence?的一个扩展方法,我们可以看一下它的源码。@ernal.InlineOnly
public
inline
fun
CharSequence?.isNullOrEmpty():
Boolean
{
contract
{
returns(false)
implies
(this@isNullOrEmpty
!=
null)
}
return
this
==
null
||
this.length
==
0
}contract这个契约方法这边我们不需要注意,不影响。主要是看returnthis==null||this.length==0这句话。它先是判断了this是否为空,然后再判断this的长度。根据我们上面讲的扩展函数的本质,我们可以很好的理解,为什么null可以调用这个方法的原因。因为上面的代码转为Java代码后是这样子的。
public
static
final
boolean
isNullOrEmpty(@Nullable
CharSequence
$this$isNullOrEmpty)
{
int
$i$f$isNullOrEmpty
=
0;
return
$this$isNullOrEmpty
==
null
||
$this$isNullOrEmpty.length()
==
0;
}我们在用null调用这个扩展方法时,其实是将null作为一个参数传入这个方法中,先判断参数是否为null,再进行下一步判断,这当然不会崩溃。扩展不能真正的修改他们所扩展的类。通过定义一个扩展,你并没有在一个类中插入新成员,仅仅是可以通过该类型的变量用点表达式去调用这个新函数,并将自身作为参数传入。扩展属性扩展属性和扩展函数类似,再举上面Person的例子,我们对Person类稍作修改,为其增加birthdayYear字段,表示其出生的年份。class
Person(val
name:
String,
val
birthdayYear:
Int)
{
fun
eat()
{
Log.i(name,
"I'm
going
to
eat")
}
fun
sleep()
{
Log.i(name,
"I'm
going
to
sleep")
}
}我们现在要为Person增加年龄age的属性,但是不改Person类,怎么实现呢。和扩展函数一样,在其他文件中声明如下。const
val
currentYear
=
2019
val
Person.age:
Int
get()
=
currentYear
-
this.birthdayYear我们通过当前年份减去生日年份计算出Person的年龄。可以看到,age是一个属性,而不是方法。这样我们就为Person增加了一个扩展属性。可以看看它转化为Java代码后的样子,和扩展函数没啥区别。@Metadata(
mv
=
{1,
1,
15},
bv
=
{1,
0,
3},
k
=
2,
d1
=
{"\u0000\u0010\n\u0000\n\u0002\u0010\b\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0003\"\u000e\u0010\u0000\u001a\u00020\u0001X\u0086T¢\u0006\u0002\n\u0000\"\u0015\u0010\u0002\u001a\u00020\u0001*\u00020\u00038F¢\u0006\u0006\u001a\u0004\b\u0004\u0010\u0005¨\u0006\u0006"},
d2
=
{"currentYear",
"",
"age",
"Lcom/chaochaowu/kotlinextension/Person;",
"getAge",
"(Lcom/chaochaowu/kotlinextension/Person;)I",
"app_debug"}
)
public
final
class
PersonExtensionsKt
{
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年饮料、酒及酒精专用原辅料合作协议书
- 初中物理力学教学创新设计方案
- 安全员生产考核题库及答案解析
- 小学生数学期中测试卷样题
- 幼儿园环保主题教育活动总结范文
- 瑞典学前教育体系改革与一体化的实践分析
- 电子科技大学英语写作辅导资料
- 财产安全防范知识题库及答案解析
- 人卫版儿科护理正高题库及答案解析
- 井下其他从业人员考试及答案解析
- 离婚协议书下载电子版完整离婚协议书下载
- GB/T 37864-2019生物样本库质量和能力通用要求
- GB 19761-2020通风机能效限定值及能效等级
- 蚁群算法最全集课件
- 初中数学北师大九年级上册图形的相似-相似三角形的性质 市一等奖PPT
- “20道游标卡尺题目及答案”
- 水利参考文件-土方回填检验批
- 铁路典型事故的案例分析课件
- 五年级上册英语课件-Project1 An animal school(第一课时)|译林版(三起) (共19张PPT)
- 高中珍惜时间主题班会课件
- 六年级上册美术课件-第8课 字体的变化丨赣美版 (24张PPT)
评论
0/150
提交评论