LCODER之架构系列:Kotlin

190 阅读8分钟

Kotlin学习网站:

Android 开发者 | Android Developers

Kotlin Programming Language

Kotlin语法

Kotlin基础语法

1. var和val

var 定义可变变量
val 定义不可变变量 优先使用

2. 类型推导

编译器可以在不显式声明类型的情况下,自动推导出它所需要的类型。

var infoStr = "AAA"  // 相当于 var infoStr : String = “AAA”
var infoChar = 'A'   // 相当于 var infoChar : Char = 'A'
var infoInt = 99  // 相当于 var infoInt : Int = 99;

Kotlin 是一种静态语言,在编译期就确定了是什么类型的变量,后续就没有办法再更改变量的类型。

3. 函数

// Unit == Void
fun main():Unit{
add(1,2)
}

// 返回值类型放在函数名后 代码块式函数体
fun add(num1:Int,num2 : Int) : Int{
return num1 + num2
}

// 返回类型 经过类型推导 : Int  表达式函数体
fun add1(num1:Int,num2 : Int) = num1 + num2

// 返回类型 类型推导 : String
fun add2() = "AAA"

// 可变参数 使用vararg关键字
fun lenMethod(vararg value : Int){
}

lambda表达式函数

val addMethod : (Int , Int) -> = {num1,num2 -> num1 + num2}

// 使用
fun main():Unit{
val r = addMethod(1,2)
}

4. 字符串模板

fun main(){
    val age = 28
    val name = "AAA"
    val sex = 'M'

    println("name : $name, age : $age, sex : $sex")

    // 换行
    val infoMessage = """
        AAAA
        BBBB
        CCCC
        DDDD
        EEEE
    """.trimIndent()
    println(infoMessage)
    
    // 打印$符号
    val price = """
    ${"$"}99999
    """.trimIndent()
    
}

5. NULL检查机制

使用"?"判断是否为null

var info : String? = null;
println(info?.length) // 如果为null ?之后的不执行

// :Int? 允许返回null
fun testMethod():Int?{
     return null
}

6. 区间

“in” 关键字

for(i in 1..9){
    
}

// 从大到小
for(i in 9 downTo 1){

}

// 跳2步执行 
for(i in 1..9 step 2){

}

// 排除最后一个元素
for(i in 1 until 10){

}

7. 比较

== 比较值本身
=== 比较对象地址

val name1 :String = "张三"
val name2 : String = "张三"

// 比较值本身
println(name1.equals(name2))
println(name1 == name2)

// 比较对象地址
println(name1 === name2)

8.数组

val number :Array<Int> = arrayOf(1,2,3,4,5,6,7,8,9)
println(number[0])
println(number[1])

for (num : Int in number){
    println(num)
}

// {value : Int -> (value + 200)} 定义一个Int类型的value 输出value + 200
val number2 : Array<Int> = Array(10,{value : Int -> (value + 200)})
for (value : Int in number2){
    println(value)
}

9. 条件判断

if和when

if:
val num1 :Int = 999
val num2 : Int = 888

val maxValue : Int = if(num1 > num2) num1 else num2
println(maxValue)

val max : Int = if(num1 > num2 ){
    println()
    num1
}else{
    println()
    num2
}
println(max)

when:
        val number = 5
        when(number){
            1 -> println("一")
            2 -> println("一")
            3 -> println("一")
            4 -> println("一")
            5 -> println("一")
            else -> println("其他")
        }


        // Any 相当于 Java中的Objcet
        val number1 = 100
        val result : Any = when(number1){
            in 1..100 -> {
                println("1..100")
                "200"
            }
            in 101..500 ->{
                println("101..500")
                true
            }
            else -> {
                println("其他")
                99  // 返回值 判断返回类型
            }
        }
        println(result)



10. 类和对象

// class Person(id:Int) 这样写 是 public final class Person 是无法继承的 
// 要想继承 需要在前面加上open
open class Person(id:Int) // 主构造函数
{
    // 次构造函数 必须引用主构造函数
    constructor(id:Int,name:String):this(id){}

    // 次构造函数
    constructor(id: Int,sex:Char):this(id){}

    // 次构造函数
    constructor():this(1234){}
    
}

// Student 继承 Person
class Student(id:Int) : Person(id) {

    // 在kotlin中,所有的变量没有默认值 所以要使用就必须先给出默认值 这一点与Java有区别

    // 使用lateinit懒加载 可以先不加载 等到要使用的时候再加载 要使用的时候必须赋值
    lateinit var name :String
    var age:Int = 0;
}

11. 抽象类和接口

// 接口
interface CallBack {

    fun testMethod():Boolean
}

// 抽象类 abstract 有 open的作用
abstract class Person() : CallBack
{
    abstract fun test1():Int

    abstract fun test2()

}

class Student() : Person() {
    override fun test1(): Int {
        TODO("Not yet implemented")
    }

    override fun test2() {
        TODO("Not yet implemented")
    }

    override fun testMethod(): Boolean {
        TODO("Not yet implemented")
    }
}

12 data数据类

相当于Java中的JavaBean

// data 数据类 相当于 Java中的JavaBean  查看自动生成的Java代码 Tool-> kotlin -> show kotlin Bytecode 
data class Person2(val id:Int,val name:String,val sex:Char)

自动生成的Java代码

public final class Person2 {
   private final int id;
   @NotNull
   private final String name;
   private final char sex;

   public final int getId() {
      return this.id;
   }

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

   public final char getSex() {
      return this.sex;
   }

   public Person2(int id, @NotNull String name, char sex) {
      Intrinsics.checkNotNullParameter(name, "name");
      super();
      this.id = id;
      this.name = name;
      this.sex = sex;
   }

   public final int component1() {
      return this.id;
   }

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

   public final char component3() {
      return this.sex;
   }

   @NotNull
   public final Person2 copy(int id, @NotNull String name, char sex) {
      Intrinsics.checkNotNullParameter(name, "name");
      return new Person2(id, name, sex);
   }

   // $FF: synthetic method
   public static Person2 copy$default(Person2 var0, int var1, String var2, char var3, int var4, Object var5) {
      if ((var4 & 1) != 0) {
         var1 = var0.id;
      }

      if ((var4 & 2) != 0) {
         var2 = var0.name;
      }

      if ((var4 & 4) != 0) {
         var3 = var0.sex;
      }

      return var0.copy(var1, var2, var3);
   }

   @NotNull
   public String toString() {
      return "Person2(id=" + this.id + ", name=" + this.name + ", sex=" + this.sex + ")";
   }

   public int hashCode() {
      int var10000 = Integer.hashCode(this.id) * 31;
      String var10001 = this.name;
      return (var10000 + (var10001 != null ? var10001.hashCode() : 0)) * 31 + Character.hashCode(this.sex);
   }

   public boolean equals(@Nullable Object var1) {
      if (this != var1) {
         if (var1 instanceof Person2) {
            Person2 var2 = (Person2)var1;
            if (this.id == var2.id && Intrinsics.areEqual(this.name, var2.name) && this.sex == var2.sex) {
               return true;
            }
         }

         return false;
      } else {
         return true;
      }
   }
}

自动生成了set、get,equals、hashCode、toString、copy等方法

12. 单例

// Object修饰的类 就是单例的 只会实例化一次
object Obj {
}

单例的第一种写法:

class Manager {

    object Holder{
        var instance = Manager()
    }

    // 派生操作 相当于Java中的static
    companion object{
        fun getInstance() : Manager = Holder.instance
    }

    // 方法
    fun show(name:String){
        println("show:$name")
    }

}

// 调用
fun main(){
    val manager = Manager.getInstance()
    manager.show("KimLiu")
}

单例的第二种写法:

class Manager2 {

    companion object{
        private var instance : Manager2? = null // 可以为null

        fun getInstance() : Manager2?{
            if (instance == null){
                instance = Manager2();
            }
            return instance

            // 另外一种写法 自己负责instance为null的情况,确保instance不为null
            return instance!!
        }
    }
    // 方法
    fun show(name:String){
        println("show:$name")
    }
}

fun main(){
    val manager : Manager2? =  Manager2.getInstance()
    manager?.show("KimLiu")
}

13.内部类

使用inner关键字

class Test {
    
    // 加了inner 是内部类 不加inner是嵌套类
    inner class innerClass{
        
    }
    
}

Kotlin高级

1. Kotlin和Java相互调用

1.1 Java调用Kotlin代码

Kotlin代码:

class MyUtils {
  fun show(info: String) {
        println(info)
    }
}

// MyUtils.kt 写了一个show      MyUtilsKt
fun show(info: String) {
    println(info)
}

Java代码:

public class Client {

    public static void main(String[] args) {
        // 这个show方法是kotlin方法 使用Java调用Kotlin方法时,会自动生成MyUtilsKt类
        MyUtilsKt.show("Derry1");

         // MyUtils类里面的方法
        new MyUtils().show("new Derry2");
    }

}

1.2 Kotlin调用Java代码

Kotlin代码:

class ClientKT {

   

}

fun main(){
    // in在KT中是关键字 在KT中使用`in` 解决冲突
    StudentJava.`in`

    // 在KT中调用Java代码 返回值是String! 因为有!所以要用一个变量接收 有可能为空
    var str:String? = StudentJava().string
    str?.length

    // 在KT中传入Java Class 需要使用 StudentJava::class.java
    showClass(StudentJava::class.java)
    // 在KT中传入KT Class 使用StudentKT::class
    showClass2(StudentKT::class)
}

fun showClass(clazz:Class<StudentJava>){

}

fun showClass2(clazz:KClass<StudentKT>){

}

Kotlin调用Java的回调 Java的CallBack

public interface JavaCallBack {
    void show(String info);
}

public class JavaManager {

    public void setCallBack(JavaCallBack javaCallBack){
        javaCallBack.show("===");
    }

}

kotlin调用Java的回调

JavaManager().setCallBack(JavaCallBack {
    print(it)
    // TODO
})

JavaManager().setCallBack(object :JavaCallBack{
    override fun show(info: String?) {
        TODO("Not yet implemented")
    }
})

JavaManager().setCallBack { TODO("Not yet implemented") }

  val callback2 = JavaCallBack { info -> println(info) }
    JavaManager().setCallBack(callback2)

Kotlin调用Kotlin的回调

KTManager().setCallBack(object:KTCallBack{
    override fun show(info: String) {
        TODO("Not yet implemented")
    }
})

val callBack3 = object : KTCallBack{
    override fun show(info: String) {
        TODO("Not yet implemented")
    }
}
KTManager().setCallBack(callBack3)

2. Kotlin代码和Java代码隔离

Kotlin中,支持使用特殊符号给函数命名,只要Java不认识Kotlin的函数名,就无法调用Kotlin的函数

`showTest`();
`4325436465375`("Derry");
`   `('M');

3. 解构声明

有时把一个对象解构成很多变量会很方便,例如:val (name, age) = person,这种语法称为 解构声明 。 在声明数据类的时候,会自动生成componentN()方法,对应按声明顺序出现的所有属性,如name就是component1()age就是component2(),而解构声明的val (dName, dAge)事实上就是调用component1()component2()方法。

写一个例子:

class Student(var id: Int,var age:Int,var name : String)
{
    // 解构
  operator fun component1() : Int = id

  operator fun component2(): Int = age

  operator fun component3(): String = name
  
  operator fun component4(): String = "-----"

}

fun main(){
    val stu = Student(1111,222,"Name")
    val(n1,n2,n3,n4) = stu

    println("n1 : $n1,n2 : $n2,n3 : $n3,n4 : $n4")
}

Kotlin高阶函数

高阶函数: 接收另一个函数(函数类型)作为参数,或返回值的类型是另一个函数。

1. 认识第一个高阶函数

fun main(){
    show(true){
        'S'
    }
    show(false){
        'F'
    }
}

/**
 * 高阶函数:
 * 参数是另一个函数 loginMethod:(Boolean)->Char
 */
fun show(isLogin:Boolean,loginMethod:(Boolean)->Char){
    if(isLogin){
        println("登陆成功")
        val r = loginMethod(true)
        println(r)
    }else{
        println("登陆失败")
        val r = loginMethod(false)
        println(r)
    }
}

2.Lamba表达式

fun main(){

    // 1.空参 空返回值 没有具体实现的函数,不能调用
    var m1:()->Unit

    // 2. 没有具体实现 不能调用
    var m2 :(Int , Int) -> Int

    var m3 :(String , Double) -> String

    var m4 :(String,Double?) -> Any?

    // n1 n2 代表两个参数  返回值是n1+n2
    var m5 :(Int , Int) -> Int = { n1 ,n2 -> n1+n2 }
    println(m5(1,2))

    var m6 = { n1:Int,n2:Int -> n1 + n2 }
    println(m6(1,2))

    // str1,str2 代表的是两个参数  ->右边的是方法的具体实现
    var m7 : (String ,String) -> Unit = {
            str1,str2 ->
        println("str1 :$str1,str2:$str2")
    }
    m7("1","2")

    // 把参数 str 返回回去
    var m8 :(String) -> String = { str -> str}
    println(m8("m8"))

    // it 代表的是 参数
    var m9 : (Int) -> Unit = {
        when(it){
            1 -> println("yi")
            in 2..100 -> println("区间")
            else -> println("其他")
        }
    }

    // a,b,c 代表的是三个参数 ->右边的是方法的具体实现
    var m10 : (Int,Int,Int) -> Unit = {
            a,b,c ->
        println("a : $a , b : $b, c: $c")
    }

    var m11 = { println("m11")}

    // sex 是参数 这样写等同于写在()里
    var m12 = {sex : Char -> if(sex == 'M') "Man" else "Woman"}
    println(m12('M'))

    // 覆盖函数
    var m13 = {n1: Int -> println("m13 : $n1")}
    // 覆盖
    m13 = { println("覆盖 $it")}
    println(m13(999))

    // 要打印 又要返回值
    var m14 = {n1 : Int -> println("打印:$n1")
        n1 + 10000
    }
    println(m14(88))
}

3. 高阶函数

无返回值的高阶函数

// 函数的调用
// {} 中的内容 就是 responseResult:(Boolean) -> Unit 的实现  it就是传入的Boolean类型的参数
login("aaa","bbb"){
    // 这里是高阶函数的实现
    if(it) println("登录成功") else println("登录失败")
}

// 对外暴露的登录方法  responseResult 是高阶函数的方法名
fun login(userName:String,pwd:String,responseResult:(Boolean) -> Unit){
    loginEngine(userName, pwd, responseResult)

}

// 私有的 不对外暴露的登录方法 
private fun loginEngine(userName:String,pwd:String,responseResult:(Boolean) -> Unit){

    // 在这里进行登录操作
    val DB_USER_NAME = "aaa";
    val DB_USER_PWD = "bbb";

    if(userName == DB_USER_NAME && pwd == DB_USER_PWD){
        // TODO 登录成功
        responseResult(true)
    }else{
        // TODO 登录失败
        responseResult(false)
    }
}

有返回值的高阶函数

// 有返回值的高阶函数
login1(){
    true // 这个就是高阶函数的返回值
}

// 有返回值的高阶函数
fun login1(mm:()->Boolean){

}

源码中常用的高阶函数

// T 调用myRun的类型 也就是myRun是T的扩展函数
// mm 是高阶函数的函数名 高阶函数是T的匿名函数 返回值为R
fun <T,R> T.myRun(mm : T.() -> R) : R{
    return mm()
}

fun main(){
       
        // 调用myRun
        val name = "aaaa"
        // name是String类型,这里的T == String
        // 那么这里的调用高阶函数就是T.length 也就是name.length 返回值是根据{}里的高阶函数实现返回的
        name.myRun {
            length
        }
    }
// 高阶函数是 T的匿名函数 也就是input.mm()
// 返回值是高阶函数的返回值 
fun <T,R> myWith(input:T,mm:T.() -> R) : R{
    return input.mm()
}

// 调用myWith
 fun main(){
       
        myWith("aaaaa"){
            // 这里是高阶函数的实现
            length  // 这里相当于 "aaaaa".length
        }
    }

根据传入的参数,确定是否执行高阶

fun onRun(isRun:Boolean,mm:() -> Unit){
    if(isRun) mm()
}

fun main(){
       
        onRun(true){
            // 这里是高阶函数的实现
            println("执行")
        }
    }

// TODO

4. Kotlin中的out和in关键字

4.1 Java中的泛型读写模式