Kotlin笔记

429 阅读4分钟

Class与KClass

扩展函数

基本使用

定义一个Person类

class Person{

}

在Expand.kt文件定义Person类扩展函数


fun Person.name(name: String) {
    println(name)
}

fun Person.age(age: String) = println(age)

kotlin使用扩展函数


val person = Person()
person.name("zhang")
person.age("97")

java使用扩展函数

Person person = new Person();
ExpandKt.name(person,"zhang");
ExpandKt.age(person,"97");

扩展函数的静态解析

扩展函数支持多态吗?

扩展函数是静态添加的,不具有运行时的多态效应

open class Animal
class Dog : Animal()


fun Animal.name(): String = "animal"
fun Dog.name(): String = "dog"


fun Animal.printName(animal: Animal) {
    println(animal.name())
}

fun main() {
    val dog = Dog()
    dog.printName(dog)
}


转为java,会强转为Animal,所以不支持多态

  public static final void main() {
      Dog dog = new Dog();
      printName((Animal)dog, (Animal)dog);
   }

Lambda

// lambda写法
var say = { name: String, age: Int ->
    println("my name is $name,and I am $age")
}
// 函数写法
fun say1(name: String, age: Int): Unit {
    println("my name is $name,and I am $age")
}

fun main() {
    say("zhang", 97)
    say1("zhang", 97)
}

my name is zhang,and I am 97

my name is zhang,and I am 97

最多22个参数


var sayMany = { p1: String, p2: String, p3: String,
                p4: String, p5: String, p6: String, p7: String, p8: String, p9: String, p10: String, p11: String, p12: String,
                p13: String, p14: String, p15: String, p16: String, p17: String, p18: String, p19: String, p20: String, p21: String,
                p22: String//如果这里有p23:String,会报错说没有Function23
    ->
    println("my name is $p1")
}

sayMany("a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a")

my name is a

新版本kotlin解决了这个问题,我的的这个版本参数是可以超越22的,原因如下

var sayMany = { p1: String, p2: String, p3: String,
                p4: String, p5: String, p6: String, p7: String, p8: String, p9: String, p10: String, p11: String, p12: String,
                p13: String, p14: String, p15: String, p16: String, p17: String, p18: String, p19: String, p20: String, p21: String,
                p22: String, p23: String, p24: String
    ->
    println("my name is $p1")
}

转为java

static {
      say = (Function2)null.INSTANCE;//两个参数的
      sayMany = (FunctionN)null.INSTANCE;//22参数以上的
   }

高阶函数

// 高阶函数,参数或者返回值,是一个函数(或者Lambda)

fun onlyif(isDebug: Boolean, block: () -> Unit) {
    if (isDebug) {
        block()
    }
}

fun main() {
    onlyif(true) { println("打印日志") }
}

如何把函数作为参数传递给另一个函数:函数的引用

// 1. 定义一个runnable对象
val runnable = Runnable {
    println("Runnable::run 这是一个函数引用 ::")
}
// 2. 声明一个函数叫做 function,这个函数类型是 ()->Unit
val function: () -> Unit
// 3. 现在要给function这个函数赋值,这个值必须也是一个函数,并且类型也是()->Unit
// function = runnable.run()//不能这样写,runnable.run()表示把执行结果赋值给了function
function = runnable::run//这就对了,把函数的引用赋值给function

onlyif(true, function)

Runnable::run 这是一个函数引用 ::

用内联优化代码 关键字:inline(类似于布局里的include)

白话kotlin:内联函数助你提升运行效率

对比下面的代码,区别只是在高阶函数onlyif之前加了一个inline

inline fun onlyif(isDebug: Boolean, block: () -> Unit) {
    if (isDebug) {
        block()
    }
}

fun main() {
    onlyif(true) { println("打印日志") }

}

fun onlyif1(isDebug: Boolean, block: () -> Unit) {
    if (isDebug) {
        block()
    }
}

fun main() {
    onlyif1(true) { println("打印日志") }

}

但是不建议到处使用inline,一般只是在高级函数前面使用,用他的目的是为了减少不必要的由Lambda表达式带来的匿名对象 过度使用inline会给编译器带来负担,查找问题变得复杂,不建议乱用这inline

构造函数

主构造函数

写在类声明的地方

open class Person(name: String)

class Man(name: String) : Person(name){
    init {
        println("构造函数执行时,我会执行的 $name")
    }
}

fun main() {
    Man("zhang")
}

次构造函数

如果由多个构造函数,第二个构造函数通过次构造函数实现,写到类内部

次构造函数,必须直接或间接调用该类主构造函数,或者改类的父类构造函数

open class Person(name: String) 

class Man(name: String) : Person(name) {
    private var age: Int = 0
    private var address: String = ""

    init {
        println("构造函数执行时,我会执行的 $name")
    }

    constructor(name: String, age: Int) : this(name) {
        this.age = age
    }

    constructor(name: String, age: Int, address: String) : this(name,age) {
        this.address = address
    }

}

fun main() {
    Man("zhang")
    Man("zhang", 97)
    Man("zhang", 97, "beijng")
}

伴生对象

类似java静态


class StringUtils{
    companion object{
        fun isEmpty(str: String): Boolean {
          return str.isEmpty()
        }
    }
}

fun main() {
    val empty = StringUtils.isEmpty("")
}

如果java里想像静态一样使用这个伴生对象方法,要加上@Jvmstatic

class StringUtils {
    companion object {
        @JvmStatic
        fun isEmpty(str: String): Boolean {
            return str.isEmpty()
        }
}

public class JavaC {
    public static void main(String[] args) {
        StringUtils.isEmpty("str");
    }
}

使用伴生对象的单例模式写法(推荐写法)

当然直接使用object也行

class Single private constructor() {
    companion object {
        fun get(): Single {
            return Holder.instance
        }
    }

    private object Holder {
        val instance = Single()
    }
}

动态代理(by)

java 的写法是很繁琐的


interface Drive {
    fun driving()
}

class MiShu : Drive {
    override fun driving() {
        println("我是秘书,我在开车。。。")
    }
}

// Manager代理类,Mishu被代理类,他们都实现Drive接口
// 经理自己不用实现开车方法,,他是用的是秘书的开车方法
class Manager(drive: Drive) : Drive by drive {

}

fun main() {
    Manager(MiShu()).driving()
}

我是秘书,我在开车。。。

interface Drive {
    fun driving()
}

class MiShu : Drive {
    override fun driving() {
        println("我是秘书,我在开车。。。")
    }
}

// Manager代理类,Mishu被代理类,他们都实现Drive接口
//一旦经理自己实现了开车方法,那么就是经历自己开车了
class Manager(drive: Drive) : Drive by drive {
    override fun driving() {
        println("我是经理,我在开车。。。")
    }

}

fun main() {
    Manager(MiShu()).driving()
}


我是经理,我在开车。。。