Kotlin 扩展函数 & 扩展属性

Kotlin 扩展函数 & 扩展属性

概述

  • Kotlin的扩展指给类增加新的功能。
  • 从语法角度可分为两种:扩展函数、扩展属性。
  • 从作用域角度可分为:顶层扩展和类内扩张。

在 Kotlin 中,几乎所有的类都可以被扩展,包括普通类、单例类、密封类、枚举类、伴生对象,甚至还包括第三方提供的 Java 类。除了匿名内部类,由于它本身不存在名称,我们无法指定“接收者类型”,所以不能被扩展。

扩展的主要用途,就是用来取代 Java 当中的各种工具类,比如 StringUtils、DateUtils 等等。

顶层扩展

扩展函数

扩展函数是指从类的外部扩展出一个函数,这个函数看起来像类的成员方法一样。

顶层扩展的本质就是类似于Java中的工具类+静态方法

  • 定义扩展函数需要使用fun关键字。
  • 接收者:如String.就是接收者,指扩展函数的接收方,代表这个扩展函数属于这个类的。
  • 扩展函数中的方法体是可以省略this
// 扩展函数
fun String.lastElement(): Char? {
    if (isEmpty()) {
        return null
    }
    return get(length - 1)
}

fun main() {
    val msg = "hello world"
    val last = msg.lastElement()
    println(last) //d
}

转换为Java代码

public final class DemoKt {
   @Nullable
   public static final Character lastElement(@NotNull String $this$lastElement) {
      Intrinsics.checkNotNullParameter($this$lastElement, "$this$lastElement");
      CharSequence var1 = (CharSequence)$this$lastElement;
      boolean var2 = false;
      return var1.length() == 0 ? null : $this$lastElement.charAt($this$lastElement.length() - 1);
   }

   public static final void main() {
      String msg = "hello world";
      Character last = lastElement(msg);
      boolean var2 = false;
      System.out.println(last);
   }

   public static void main(String[] var0) {
      main();
   }
}

说明:

  • String类型的扩展函数lastElement()被编译器转换为静态方法,同时多了一个String类型的参数。
  • 调用msg.lastElement()的地方被编译器转换为静态方法的调用ExtKt.lastElement(msg)

扩展属性

扩展属性指在类的外部定义一个新的成员属性。

//扩展属性
val String.lastElement
    get() = if (isEmpty()) {
        null
    } else {
        get(length - 1)
    }


fun main() {
    val msg = "hello world"
    val last = msg.lastElement
    println(last) //d
}

转换为Java代码

public final class DemoKt {
   @Nullable
   public static final Character getLastElement(@NotNull String $this$lastElement) {
      Intrinsics.checkNotNullParameter($this$lastElement, "$this$lastElement");
      CharSequence var1 = (CharSequence)$this$lastElement;
      boolean var2 = false;
      return var1.length() == 0 ? null : $this$lastElement.charAt($this$lastElement.length() - 1);
   }

   public static final void main() {
      String msg = "hello world";
      Character last = getLastElement(msg);
      boolean var2 = false;
      System.out.println(last);
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }
}

说明:

  • 扩展属性被编译器转换为静态方法。

由于 JVM 不理解 Kotlin 的扩展语法,所以 Kotlin 编译器会将扩展函数转换成对应的静态方法,而扩展函数调用处的代码也会被转换成静态方法的调用。

类内扩展

类内的扩展,外面是无法访问的,只能被类内的成员访问。

class Person {
    var name: String = ""
    var age: Int = 0
}

class Helper {
    val Person.isAult: Boolean
	    get() = age >= 18

    fun Person.sayHello() {
        println("say hello")
    }

    fun test() {
        val person = Person()
        println(person.isAult)
        person.sayHello()
    }
}
fun main() {
    val person = Person()
    //    person.isAult //编译器报错
    //    Person.sayHello() //编译报错

    val helper=Helper()
    helper.test()
}

转换为Java代码

public final class Person {
    @NotNull
    private String name = "";
    private int age;

    @NotNull
    public final String getName() {
        return this.name;
    }

    public final void setName(@NotNull String var1) {
        this.name = var1;
    }

    public final int getAge() {
        return this.age;
    }

    public final void setAge(int var1) {
        this.age = var1;
    }
}


public final class Helper {
    public final boolean isAult(@NotNull Person $this$isAult) {
        return $this$isAult.getAge() >= 18;
    }

    public final void sayHello(@NotNull Person $this$sayHello) {
        String var2 = "say hello";
        System.out.println(var2);
    }

    public final void test() {
        Person person = new Person();
        boolean var2 = this.isAult(person);
        System.out.println(var2);
        this.sayHello(person);
    }
}

说明:

类内扩展方法和属性会被Kotlin编译器转换为类的成员方法,不属于类的成员,所以外界不能访问。

扩展的局限性

  • Kotlin的扩展的不是真正的类成员,因此它无法被子类重写。
  • 扩展属性不能存储数据,其本质是静态方法。
  • 扩展可以访问同文件下的属性和方法,其他文件则不行;不能访问接收者类型的非private、protected成员。根本原因仍是类+静态方法的形式。

优先级问题

情况优先级
成员方法与扩展函数成员方法
子类成员方法与父类扩展函数子类成员方法
子类扩展函数与父类成员方法父类成员方法

优化封装SP

fun SharedPreferences.edit(commit: Boolean = false, action: SharedPreferences.Editor.() -> Unit) {
    val editor = edit()
    action(editor)
    if (commit) {
        editor.commit()
    } else {
        editor.apply()
    }
}
//懒加载初始化
private val preference: SharedPreferences by lazy {
    getSharedPreferences("APP", Context.MODE_PRIVATE)
}

//调用
preference.edit {
    putString("name", "Tom")
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值