写点什么

Kotlin 函数和扩展 (extension)

作者:子不语Any
  • 2022-11-28
    湖南
  • 本文字数:1234 字

    阅读完需:约 4 分钟

Kotlin函数和扩展(extension)

前言

本文巩固一下 Kotlin 函数扩展知识点。

本文大纲

1. 回顾 Java 中 Utils 工具类

Utils 是无构造参数的 static 方法集合,主要用于扩展某个对象的功能,如 MathUtils,StringUtils, LogUtils。


Utils 类在一定程度上减少了重复代码的问题,是成本最低的 DRY(Don't repeat yourself)实践。


从代码设计的角度看,Utils 方法是 static 的,没有 OOP 的继承,重写,抽象的特性(static 本身就是反 OOP 的)。且 Utils 违反了单一职责,一个类应该包含其属性和所有操作方法。而 Utils 实现的方法并不在这个类内。


从使用的角度,必须预先知道 Utils 工具类的存在,能使用为这个类添加的扩展方法。 但在实际使用中,这个条件往往是缺失的,在团队开发中,个人无法掌握所有代码,因为不知道这个代码已经有人实现过了,导致都实现了自己的 Utils。所以会导致一个工程里同一个类的 Utils 往往会有好几个。


但存在必然是合理的。从开发者个人角度来看,使用 Utils 而不是对象继承的原因,主要是因为:


  1. 无法继承/重写这些类及其方法,只能通过 Utils 扩展;

  2. 继承一个类比抽取代码块封装为函数的实现成本+替换成本高;

  3. Utils 绝大情况下只是用来存储代码块,需求非常稳定,无需面向对象。


使用 Utils 的场景里很少会用到面向对象的特性,那么没有面向对象的缺点也并没有那么严重了。抛开 Utils 的设计缺点,是否可以避免使用上的缺点?Kotlin 提供的解决方法就是扩展(extension)。

2. Kotlin 扩展的使用和实现分析

声明一个 Kotlin 扩展如下:


// StringUtils.ktfun String.appendHaha(): String {    return this + "haha"}
复制代码


与普通的方法声明很相似,方法名前多了一个类名,表示其归属的类。扩展声明为顶层声明的时候可以被外部调用(因为函数是一等公民,在方法内部也可以声明扩展方法)。


函数体内用 this 来引用调用的实例,属性和方法的访问权限与普通调用一致。一致的意思是和正常在其他方法内部调用的权限一致,并不会因为是扩展声明就可以访问 private/propect 权限的属性和方法。这是因为扩展声明在字节码层面上其实是 static 方法。下面是appendHaha 对应 jvm 字节码的反编译结果:


public class StringUtilsKt {    @NotNull    public static final String haha(@NotNull String $this$haha) {        Intrinsics.checkParameterIsNotNull($this$haha, "$this$haha");        return $this$haha + "haha";    }}
复制代码


所以从 Java 的角度来看,Kotlin 的扩展方法和 Utils 的调用没有差别,都是调用类的 static 方法然后传入操作的参数。实际上 Java 想要调用 Kotlin 的扩展方法也确实是这样调用的。


扩展方法的调用和实例方法调用一致,在调用者角度没有区别。

3. 总结

Kotlin 扩展依然没有解决 Utils 类的设计缺点。就像 Kotlin Int 对 Java int,Kotlin property 对 Java field 一样,Kotlin 扩展是 对 Java 不完全面向对象的“清理”,使 Kotlin 更接近完全面向对象。相比 Utils 工具类,Kotlin 扩展特性能有效减少开发者心智负担和沟通成本,从而提高开发效率。

发布于: 刚刚阅读数: 4
用户头像

子不语Any

关注

If not now,when? 2022-09-17 加入

安卓攻城狮

评论

发布
暂无评论
Kotlin函数和扩展(extension)_kotlin_子不语Any_InfoQ写作社区