Kotlin基础知识_05-Kotlin标准函数_静态方法

Kotlin基础知识_05-Kotlin标准库函数&静态方法

1. 标准库函数 let(), with(), run(), apply(), repeat()

Kotlin的标准库函数类似于C语言的标准库函数,在任意的位置均能调用。

1.1 let()

image-20231102135225018

以调用的对象本身作为block函数块的参数,并且返回block函数块的结果,这个block函数块可以是一个lambda表达式,它的最后一行代码将作为返回结果:

ex:

data class Car(var color: String = "红色", var weight: Int = 20) {
    fun run() = println("This car is running")
    fun ring() = println("This car is -ringing-.")
}

fun main() {
    val car = Car()

    println("car info(before call let): $car")

    val result = car.let {
        it.color = "绿色"
        it.weight = 300
        it.run()
        it.ring()
        123
    }

    println("car info(after call let): $result")
}

输出:

car info(before call let): Car(color=红色, weight=20)
This car is running
This car is -ringing-.
car info(after call let): 123

可以看到 Lambda 表达式中的code 均得到了执行,并且返回了lambda表达式的结果:123.

1.2 with()

image-20231102140627908

在传入的对象上调用指定的block函数块,并且返回block函数块的最后一行代码。

例如,输入log时经常会用到字符串拼接:

public class Test {

    public static void main(String[] args) {
        StringBuilder builder = new StringBuilder("------------ Person Info -------------");
        builder.append("\n");
        builder.append("Name: zhangSan\n");
        builder.append("Age: 16\n");
        builder.append("Address: Beijing\n");
        System.out.println(builder);
    }

}

利用with()函数则可以简化上述code:

fun main() {
    val result = with(StringBuilder("------------ Person Info -------------")) {
        append("\n")
        append("Name: zhangSan\n")
        append("Age: 16\n")
        append("Address: Beijing\n")
        toString()
    }
    println(result)
}

输出:

------------ Person Info -------------
Name: zhangSan
Age: 16
Address: Beijing

1.3 run()

image-20231102141841100

该函数有两种实现:

一种是直接调用run()函数,传入一个函数块,然后返回该函数块的最后一行代码;

另一种是在指定的对象上调用,将该对象作为函数块的上下文,然后返回函数块的最后一行代码;

直接调用run()函数

fun main() {
    val result = run {
        println("abc")
        println("efg")
        123
    }
    println(result)
}

输出:

abc
efg
123

在对象上调用run()函数

fun main() {
    val result = StringBuilder("------------ Person Info -------------").run {
        append("\n")
        append("Name: zhangSan\n")
        append("Age: 16\n")
        append("Address: Beijing\n")
        toString()
    }
    println(result)
}

输出:

------------ Person Info -------------
Name: zhangSan
Age: 16
Address: Beijing

这里新建了一个匿名对象 StringBuilder("------------ Person Info -------------"), 然后在它身上调用 run()函数。

1.4 apply()

image-20231102142840922

在当前对象上调用指定的函数块,并且返回这个被调用的对象本身。

ex:

    val result = StringBuilder("------------ Person Info -------------").apply {
        append("\n")
        append("Name: zhangSan\n")
        append("Age: 16\n")
        append("Address: Beijing\n")
        123
    }
    println(result)

输出:

------------ Person Info -------------
Name: zhangSan
Age: 16
Address: Beijing

Note:

它和 let(), with(), run() 函数的最大区别在于,前面三个函数返回的均是传入的函数块的结果,即Lambda表达式的最后一行code, apply() 函数返回的则是调用的对象本身,比如我在上述Lambda表达式的最后一行写的是123,但是实际上打印出的result的结果是仍然是 StringBuilder()对象。

1.5 repeat()

image-20231106110438445

让指定的函数块执行N次:

ex: 在原有字符串的基础上重复添加N个相同的字符串:

fun String.repeatTimes(num: Int): String {
    val builder = StringBuilder(this)
    repeat(num) {
        builder.append(this)
    }
    return builder.toString()
}

fun main() {
    val str = "Abcd"
    val newStr = str.repeatTimes(4)
    println("newStr: $newStr")
}

输出:

newStr: AbcdAbcdAbcdAbcdAbcd

2. 静态方法

静态方法在某些编程语言里面又叫作类方法,指的就是那种不需要创建实例就能调用的方法,所有主流的编程语言都会支持静态方法这个特性。java中定义静态方法很简单,给方法加上static 关键字就行了:

public class Util {
	public static void doAction() {
		System.out.println("do action");
	}
}

调用时直接写成 Util.doAction()就能调用。

kotlin中的静态方法和java的稍有区别,分为伪静态方法和真实的静态方法两种。

2.1 伪静态方法

所谓伪静态方法,就是说它从语法结构上看起来像是一个静态方法,但实际上它不是一个静态方法,这样的定义主要会出现在以下两种语法结构中:

2.1.1 单例类

object Utils {
    fun formatString() = println("format a string")
}

fun main() {
    Utils.formatString()
}

输出:

format a string

Utils.formatString() 这种看起来跟java中的静态方法很像,都是以类.方法名的形式去调用,但实际上这个 formatString()不是静态方法。当然kotlin也推荐我们以这种单例类的方式去实现工具类,毕竟看起来像。

2.1.2 companion object

class Utils {
    fun splitString() = println("split a string")

    companion object {
        fun formatString() = println("format a string")
    }
}

fun main() {
    Utils().splitString()
    // 伴生类中的方法也可以写成类似于静态方法这种调用形式
    Utils.formatString()
}

输出:

split a string
format a string

Kotlin 规定,所有定义在companion object中的方法都可以使用类似于Java静态方法的形式调用,companion object这个关键字实际上会在Utils类的内部创建一个伴生类,而formatString()方法就是定义在这个伴生类里面的实例方法。只是Kotlin会保证Util类始终只会存在一个伴生类对象,因此调用Utils.formatString()方法实际上就是调用了Utils类中伴生对象的formatString()方法。

不过这个也不是真正的静态方法。

2.2 真实的静态方法

上面两种语法结构定义的方法其实都不是真实的静态方法,在java代码中是没有办法以类.方法名的形式去直接调用的,

比如我在kotlin文件中定义了以下两个kotlin类:

TestKotlin.kt

object ByteUtils {
    fun bytesToHexString() = println(">>>>>>>>>>>>> bytesToHexString <<<<<<<<<<<<<")
}

class StringUtils {
    fun splitString() = println("split a string")

    companion object {
        fun formatString() = println("---------------- format a string ------------")
    }
}

在java类中调用kotlin单例类的方法

编译器报错:

image-20231102152404159

直接提示 bytesToHexString()是一个非静态方法。

在java类中调用kotlin companion object 中的方法

编译器报错:

image-20231102152814503

提示在StringUtils类中根本找不到 formatString() 方法。

除非写成下面的形式, 才允许正常调用:

public class Test {

    public static void main(String[] args) {
        ByteUtils.INSTANCE.bytesToHexString();
        StringUtils.Companion.formatString();
    }

}

输出;

>>>>>>>>>>>>> bytesToHexString <<<<<<<<<<<<<
---------------- format a string ------------

如果一定要在 kotlin中定义真实的静态方法,可通过下面两种方式:

2.2.1 使用 @JvmStatic 注解

分别给上述单例类和 companion object 中定义的实例方法加上 @JvmStatic 注解:

object ByteUtils {
    @JvmStatic
    fun bytesToHexString() = println(">>>>>>>>>>>>> bytesToHexString <<<<<<<<<<<<<")
}

class StringUtils {
    fun splitString() = println("split a string")

    companion object {
        @JvmStatic
        fun formatString() = println("---------------- format a string ------------")
    }
}

然后在java代码中就可以以类名.方法名的形式去调用了:

public class Test {

    public static void main(String[] args) {
        ByteUtils.bytesToHexString();
        StringUtils.formatString();
    }

}

输出:

>>>>>>>>>>>>> bytesToHexString <<<<<<<<<<<<<
---------------- format a string ------------

给单例类或companion object中的方法加上@JvmStatic注解,那么Kotlin编译器就会将这些方法编译成真正的静态方法。

注意:

Kotlin 规定:@JvmStatic注解只能加在单例类companion object中的方法上,如果你尝试加在一个普通方法上,会直接提示语法错误。

image-20231102153525194

2.2.2 使用顶层方法

顶层方法(Top Level Method), 即没有定义在任何类中的方法,比如经常使用的main方法。Kotlin编译器会将所有的顶层方法全部编译成静态方法,因此只要你定义了一个顶层方法,那么它就一定是静态方法。想要定义一个顶层方法,首先需要创建一个Kotlin文件。对着任意包名右击 → New → Kotlin File/Class,在弹出的对话框中输入文件名即可。注意创建类型要选择File,如图所示:

image-20231102153939245

BitmapUtil

fun decodeBitmap() = println("******************* decode bitmap *****************")

decodeBitmap()将会自动成为顶层方法,在java代码中可以这样调用:

public class Test {

    public static void main(String[] args) {
        BitmapUtilKt.decodeBitmap();
    }

}

输出:

******************* decode bitmap *****************

注意:

在java里调用时仍然要以类.方法名的形式去调用,只不过这里的类名就是新建的Kotlin 文件名罢了,在kotlin里面调用则无此限制,直接写方法名即可:

object ByteUtils {
   @JvmStatic
   fun bytesToHexString() = println(">>>>>>>>>>>>> bytesToHexString <<<<<<<<<<<<<")
}

class StringUtils {
   fun splitString() = println("split a string")

   companion object {
       @JvmStatic
       fun formatString() = println("---------------- format a string ------------")
   }
}

fun main() {
   StringUtils().splitString()
   // 伴生类中的方法也可以写成类似于静态方法这种调用形式
   StringUtils.formatString()
   decodeBitmap()
}

输出:

split a string
---------------- format a string ------------
******************* decode bitmap *****************

可以看到,直接写 decodeBitmap()就行。

<完>

posted @ 2023-11-02 15:48  夜行过客  阅读(392)  评论(0编辑  收藏  举报