
?
让我们从用法到分类讲起
扩展?扩展什么呢?当然是扩展类中的属性和方法 这里厉害?看段代码吧?
1//?这就是扩展函数
2fun?String.pandaer()?{
3????println("pandaer杂货铺中的$this")
4}
5
6fun?main()?{
7????"android".pandaer()
8}
感觉扩展函数没什么特别的,和普通函数相比不就是多了 ClassType. 这里就是String. 这个我们便给他一个名字:接收者 但是如果真的能扩展一个类的属性和方法不就乱套了吗。那岂不是我想要扩展谁就扩展谁。
通过反编译看原理
1//?上述代码编译而来
2public?final?class?KTXKt?{
3???public?static?final?void?pandaer(@NotNull?String?$this$pandaer)?{
4??????Intrinsics.checkNotNullParameter($this$pandaer,?"$this$pandaer");
5??????String?var1?=?"pandaer杂货铺中的"?+?$this$pandaer;
6??????System.out.println(var1);
7???}
8
9???public?static?final?void?main()?{
10??????pandaer("android");
11???}
12
13???//?$FF:?synthetic?method
14???public?static?void?main(String[]?var0)?{
15??????main();
16???}
17}
观察逻辑 pandaer() 方法变成了一个静态方法,而接收者变成了该函数的参数。所以所谓的扩展又是语法层面的,底层的实现就是一个静态方法(顶层扩展)这让我不禁想到一句话 理想是丰满的现实是骨感的。
从底层原理看优缺点
因为底层的实现并不是真正的去扩展某个类,所以我们定义的扩展函数和扩展属性都不能被子类继承, 并非真实扩展所以就存在访问作用域的限制 拿上面代码举例,如果我要在我的pandaer()函数中调用接收者类型的私有成员,是不可能的,因为底层实现限制了这一点,传递的是一个实实在在的接收者对象,顶多调用公开的方法

?
前面都是扩展函数和扩展属性都有的缺点,而扩展属性还有一个缺点:无状态
这个我们还是从底层实现来看
1//kt
2class?Pan?{
3????var?name?:?String?=?"xixi"
4????private?fun?cry()?{
5????????println("Cry")
6????}
7????fun?smile()?{
8????????println("smile")
9????}
10}
11
12val?Pan.age?:?String
13????get()?=?name
14
15//java
16public?final?class?KTXKt?{
17???@NotNull
18???public?static?final?String?getAge(@NotNull?Pan?$this$age)?{
19??????Intrinsics.checkNotNullParameter($this$age,?"$this$age");
20??????return?$this$age.getName();
21???}
22}
属性最后还是被转换成了静态函数。所以无论是扩展方法还是扩展属性底层的实现都是静态方法(顶层扩展)
所以无状态就好理解了,就是不能自己存储数据 用kt话说没有支持字段
总结一下:
缺点:
- 不能被继承
- 访问作用域受限
- 无状态
从KT源码的设计中看优点

?
每次你没有看错KT中的源码只有45行,你会发现这些函数不够我们用啊,不是还有一些函数吗?答案是他们在Strings.kt中 在真正的String类的源码设计中只保留最核心的逻辑,一些功能性的逻辑用扩展函数来代替了。所以这就是第一个优点 关注点分离 源码的设计就是将核心逻辑 和 功能性的逻辑分离
第二个优点 : 减少模板代码
1fun?Date.format(format:String?=?"EEE,yyyy-mm-dd")?:?String?{
2????val?simFormat?=?SimpleDateFormat(format)
3????return?simFormat.format(this.time)
4}
5fun?main()?{
6????println(Date().format())
7}
比如这个例子,以前我们要格式化时间要使用一个格式类,现在直接一个扩展函数就解决问题了。
让我们补充讲讲类中的扩展

?
看上面这个代码,我在类中虽然可以写扩展函数和扩展属性,但是他好像被困在Pan类中了
看底层实现
1public?final?class?Pan?{
2???private?final?String?name?=?"pandaer";
3
4???private?final?void?f2()?{
5??????String?var1?=?"f1";
6??????System.out.println(var1);
7???}
8
9???public?final?void?f1(@NotNull?String?$this$f1)?{
10??????Intrinsics.checkNotNullParameter($this$f1,?"$this$f1");
11??????this.f2();
12???}
13
14???@NotNull
15???public?final?String?getNameKtx(@NotNull?String?$this$nameKtx)?{
16??????Intrinsics.checkNotNullParameter($this$nameKtx,?"$this$nameKtx");
17??????return?this.name;
18???}
19
20???public?final?void?text()?{
21??????String?xixi?=?this.getNameKtx("xixi");
22??????this.f1("xixi");
23???}
24}
很明显,扩展方法和属性一如既往的变成了方法不过这次是属于Pan类的成员方法,所以才被关在了Pan中。
从优缺点中看应用场景
关注点分离 可以让我们和源码设计一样 将核心逻辑和功能性的逻辑分离
比如用扩展方法替代以前在Java中的工具类
如果你还知道更多的应用场景不妨告诉我😄我们一起学习进步
|