Kotlin基础笔记

hloong 于 2021-04-05 发布

本篇笔记主要记录过去几年 工作所需Kotlin的简单基础,用来查漏补缺

0,Kotlin构建流程和设计理念

Kotlin是一种在java虚拟机上运行的静态类型编程语言 可以和java代码相互运作 在android项目中替代java或与java共存

简洁易用,安全,工具友好,可以使用java的API,代码量少

Kotlin构建流程

image

kt文件会被kotlin编译器编译成java的字节码文件.class, 字节码文件会被jar工具打包成jar包,然后被各个平台输出应用,比如安卓输出安卓app,iOS输出iOSapp

为啥需要一个kotlin的runtime运行时? 因为kotlin有自己的类库,所以最后运行的时候需要kotlin运行时来关联kotlin的类库辅助运行

1,Kotlin基本类型

数字类型

Char 字符数据类型

Boolean 数据类型

数组

关于创建数组

fun arrayTest(){
    //使用arrayOf()创建数组   系统可以推断出类型
    var result  = arrayOf("Java","Python","C++")  
     
    //创建一个元素为null的数组   需要使用泛型类指定数组类型
    var result2 = arrayOfNulls<Int>(3)
    
    //创建长度为0的空数组    需要使用泛型类指定数组类型
    var result3 = emptyArray<String>()
    
    //创建指定长度,使用Lambda表达式初始化数组元素的数组   可以动态的计算数组元素的值
    var arr4 = Array (5,{(it * 2 + 1)})
    for(item in arr4){
        print(item)// 1 3 5  7 9   
    }
    
    //如果将基本类型传入Array<T>中,Kotlin会将这些基本类型自动装箱,所以提供了了 ByteArray ShortArray等等
    //静态初始化
    var doubleArr = doubleArrayOf(1.0,2.0,6.43,3.5,4.65)
    //动态操作
    var intArr2 = IntArray(5, {it * it})
    
}

数组常用方法

var result = arrayOf(1,2,3,4)
   //使用 Lambda 表达式要求所有数组元素都满足该表达式,如果都满足,那么该方法返回 true
   print(result.all({it>2}))  //false
   
   //使用 Lambda 表达式要求其中只要有一个数组元素该表达式,如果满足,那么该方法返回 true
    print(result.any({it>3}))  //true
    
    //将数组转为集合
    print(result.asList()) //[1, 2, 3, 4]
    
    //根据数组元素来计算<K,V>对,返回所有<K,V>对组成的 Map集合
    print(result.associate({it + 10 to it* it}))//{11=1, 12=4, 13=9, 14=16}
    
    var map= mutableMapOf(5 to 100 , 2 to 120 , -1 to 130)
    print(map)//{1=100, 2=120, -1=130}
    //将数组转为map对象,并且添加到其它的map中
    print(result.associateByTo(map, {it* it})) //{1=1, 2=120, -1=130, 4=2, 9=3, 16=4}
    
    //计算数组所有元素的总和
    println(result.fold(0, {ace , e ->ace+ e})) //10
    
    //两个数组,如果长度和顺序都相等,返回true
    print(result.contentEquals(result))//true
    
    //复制数组
    var result2 = result.copyOf(6)
    print(result2.asList())//[1, 2, 3, 4, null, null]
    
    //将数组转为字符串
    print(result2.contentToString())//[1, 2, 3, 4, null, null]
    
    //将result2数组从第5(indexWie4)个到第7(index为6)个元素赋值为1
    result2.fill(1,4,6)//1是赋给的值   4和6是下标(包含4,不包含6)
    print(result2.contentToString())
    
    //对数组进行排序
    result.sort()

遍历数组

var arr = Array (5,{(it * 2 + 1)})
    for(item in arr){
        print(item)// 1 3 5  7 9   
    }
//带索引遍历数组
for(i in arr.indices){
    println("$i -> ${arr[i]}")
}
//遍历元素带索引
for((index,item) in arr.withIndex()){
    println("$index-> $item ")
}

arr.forEach{
    println(it)    
}

arr.forEachIndexed{index,item->
    println("$index -> $item")
}

Kotlin集合相关

fun collectionType(){
    //不可变集合
    val stringList = listOf("one","two","three")
    println(stringList)
    val stringSet = setOf("one","two","three")
    println(stringSet)
    //可变集合
    val num= mutableListOf(1,2,3,4,5)
    num.add(6)
    num.removeAt(1)
    num[0] = 0
    println(num)
    //mutableSetOf  会移除元素里面相同的项
    val hello = mutableSetOf("H","e","l","l","o")
    hello.remove("o")
    println(hello)
    //集合的加减操作
    hello+=setOf("w","o","r","l","d")
    println(hello)
    //Map<K,V> 不是Collection 接口的继承者,但是它是Kotlin的一种集合类型
    val numberMap:Map<String,Int> = mapOf("key1" to 1,"key2" to 2,"key3" to 3)
    println("All Keys:${numberMap.keys}")
    println("All values:${numberMap.values}")
    if("key2" in numberMap) println("Value by key Kye2:${numberMap["key2"]}")
    if(1 in numberMap.values) println("1 is in the map")
    if(numberMap.containsValue(1)) println("1 is in the map2")
    //2个具有相同键值对,但顺序不同的Map相等,无论键值对的顺序如何,包含相同键值对的2个Map是相等的
    val numberMap2 = mapOf("key2" to 2,"key3" to 3,"key1" to 1)
    println("numberMap2 == numberMap : ${numberMap2 == numberMap}")//true  == 等价于equals方法
    println(numberMap.equals(numberMap2))
    //2个具有相同元素的,但顺序不同的list相等吗?为什么?  
    val num2 = mutableListOf(2,1,3,5,4)
    println("num == num2 : ${num == num2}")//false
}

上面代码执行的结果如下

[one, two, three]
[one, two, three]
[0, 3, 4, 5, 6]
[H, e, l]
[H, e, l, w, o, r, d]
All Keys:[key1, key2, key3]
All values:[1, 2, 3]
Value by key Kye2:2
1 is in the map
1 is in the map2
numberMap2 == numberMap : true
true
num == num2 : false

集合排序

fun collectionSort(){
    val num = mutableListOf(1,5,3,4,2)
    num.shuffle()//随机排序
    println(num)
    num.sort()//从小到大
    println(num)
    num.sortDescending()//从大到小
    println(num)
    data class Language(var name:String,var score:Int)
    //单条件排序
    val languageList:MutableList<Language> = mutableListOf()
    languageList.add(Language("kotlin",10))
    languageList.add(Language("C",8))
    languageList.add(Language("java",10))
    languageList.add(Language("B",8))
    languageList.add(Language("swift",6))
    languageList.sortBy{it.score}
    println(languageList)
    //多条件排序
    languageList.sortWith(compareBy(
        {it.score},{it.name}
        )
    )
    println(languageList)
}

2,Kotlin的方法

普通方法,工具类等

fun main() {
    println("普通方法 ${funDay(99)}")
    println("普通方法2 ${fun2Day(99)}")
    Person().test1()
    Person.test2()
    println("Util.double(2) : ${Util.double(2)}")
}
//普通方法
fun funDay(days:Int):Boolean{
    return days>100
}
// 单表达式方法,当方法返回单个表达式时,可以省略花括号并且在 = 符号之后指定代码体即可,  效果同上
fun fun2Day(days:Int):Boolean = days>100

//普通类
class Person {
    fun test1(){
        println("test1 成员方法")
    }
    companion object{
        fun test2(){
            println("companion object 实现类方法,类似java的静态方法")
        }
    }
}
//工具类
object Util{
    fun double(num : Int):Int{
        return 2*num
    }
}

Lambda表达式

fun main() {
    lb()
    println("1+3= ${testLb(1,3)}")
    println("--1+3= ${tlb1(1,3)}")
    println("---1+3= ${tlb2(1,3)}")
    tlb3()
    lb2()
}

val lb = {println("lambda 无参数")}
fun testLb(a:Int,b:Int):Int{
    return a+b
}
val tlb1:(Int,Int) -> Int = {a,b -> a+b}
val tlb2 = {a:Int,b:Int -> a+b}
//tlb1 等价于 tlb2
fun tlb3(){
    val arr = arrayOf(1,2,3,5,6)
    println("filter输出第一个大于4的数据: ${arr.filter{it>4}.component1()}")
    println("打印低于5的列表数据:${arr.filter{it<5}}") 
}
//lambda可以通过_来替代不需要的参数
fun lb2(){
    val map = mapOf("key1" to 1,"key2" to 2)
    map.forEach{(key,value)->
        println(value)
    }
    map.forEach{(_,value)->
        println(value)
    }
}

执行结果为:

lambda 无参数
1+3= 4
--1+3= 4
---1+3= 4
filter输出第一个大于4的数据: 5
打印低于5的列表数据:[1, 2, 3]
1
2
1
2

Lambda高阶函数

需求1:实现一个能够对集合元素进行求和的高阶函数,并且每遍历一个集合元素要有回调

需求2:实现一个能够对集合元素进行求和的高级函数,并返回一个声明为(scale:Int)-> Float 的函数

fun main() {    
   val list = listOf(1,2,4)
   val result = list.sum{println("it:${it}")}
   println("result:${result}")
   println("result*2:${list.toIntSum()(2)}")
}
//高阶函数,函数作为参数
//需求1:实现一个能够对集合元素进行求和的高阶函数,并且每遍历一个集合元素要有回调
fun List<Int>.sum(callback:(Int)->Unit):Int{
    var result = 0
    for(v in this){
        result+=v
        callback(v)
    }
    return result
}
//函数作为返回值
//需求2:实现一个能够对集合元素进行求和的高级函数,并返回一个声明为(scale:Int)-> Float 的函数
fun List<Int>.toIntSum():(scale:Int)->Float{
    println("first Layer")
    return fun(scale):Float{
        var result = 0f
        for(v in this){
            result+= v.toInt()*scale
        }
        return result
    }
}
/**输出结果
* it:1
* it:2
* it:4
* result:7 
* first Layer
* result*2:14.0
*/

闭包

能够读取其他方法内部变量的方法,是方法内部和外部链接起来的桥梁

特性: 方法可以作为另一个方法的返回值或参数,还可以作为一个变量的值 方法可以嵌套定义,即在一个方法内部可以定义另外一个方法

好处:

实战:实现一个闭包

需求:实现一个接受一个testClosure方法,该方法要接受一个Int类型的v1参数,同时能够返回一个声明为 (v2:Int,(Int)->Unit)的函数,并且这个函数能够计算V1和V2的和

fun main() {
    testClosure(1)(2){
        println("1+2= ${it}")
    }
}
/** 闭包高阶函数
 * 需求:实现一个接受一个testClosure方法,该方法要接受一个Int类型的v1参数,
 * 同时能够返回一个声明为(v2:Int,(Int)->Unit)的函数,并且这个函数能够计算V1和V2的和
 */
fun testClosure(v1:Int):(v2:Int,(Int)->Unit)-> Unit{
    return fun(v2:Int,printer:(Int)->Unit){
        printer(v1+v2)
    }
}
//结果:1+2=3

解构声明

data class Result(val msg :String,val code:Int)
fun test(){
    var result = Result("success",0)
    val (msg,code) = result
    println("msg= ${msg},code=${code}")
}
//msg= success,code=0

方法字面值

在kotlin中,匿名方法和lambda表达式都是方法的字面值

fun literal(){
    var temp:((Int)->Boolean)?=null
    temp = {num -> (num > 10)}
    println("temp(11): ${temp(11)}")
}
//temp(11): true

3,Kotlin的类与接口

构造方法

/**
 * 主构造方法
 */
class KotlinClass constructor(name:String){
    /**
     * 次构造方法
     */
    constructor(v:Int,name:String):this(name){
        println("name1--$name")
    }
    constructor(b:Char,v:Int,name:String):this(name){
        println("name2--$name")
    }
}

继承和覆盖,属性GetSet方法

fun main(){
    Cat(10)
    Dog(5).eat()
    println("School is open:${School().isOpen} and ${School().score}") 
    Test().test()
}

open class Animal(age:Int){
    init{
        println(age)
    }
    open fun eat(){}
    open val foot:Int = 0
}
//派生类有主构造方法的情况
class Cat(age:Int):Animal(age){
}
//派生类无主构造方法的情况
class Dog:Animal{
    constructor(age:Int):super(age)
    override val foot:Int = 4
    override fun eat(){
        println("dog eat $foot")
    }
}
/**
 * 属性的声明
 */
class School{
    val name:String="Middle"
    val numSudent:Int = 1000
    val isOpen:Boolean
        get() = numSudent > 900
    var score:Float = 0.0f
        get()= if(field<0.2f) 0.2f else field * 1.2f
        set(value){ 
            println(value) 
        }
}
class Test{
    lateinit var school:School
    fun setUp(){
        school = School()
    }
    fun test(){
        if(::school.isInitialized) {
            println(school.isOpen)
        }else{
            println(false)
        }
    }
}
/**返回结果
 * 10
 * 5
 * dog eat 4
 * School is open:true and 0.2
 * false
 */

抽象类

abstract class Printer{
    abstract fun print()
}
class FilePrinter:Printer(){
    override fun print(){
        println("print file")
    }
}

接口

//kotlin和java的接口定义区别,kotlin可以在接口里面做方法实现
interface Study{
    fun discuss()
    fun learnCourses(){
        println("learn^")
    }
}
class StudyA:Study{
    override fun discuss(){
        println("discuss")
    }
}

继承多个接口里面有相同的方法,怎么复写?

//继承多个接口里面有相同的方法,怎么复写?需要在super后面添加参数接口
interface A{
    fun foo(){
        println("A")
    }
}

interface B{
    fun foo(){
        println("B")
    }
}

class D:A,B{
    override fun foo(){
        super<A>.foo()  
    }
}

数据类

数据类是一个简单的类,用于保存数据/状态并包含标准功能(函数)。 data关键字用于将类声明为数据类。

//数据类内部有以下函数,它消除了反复套用的代码
equals(): Boolean
hashCode(): Int
toString(): String
component() 函数对应的属性
copy()

class Product1(var item: String, var price: Int)
data class Product2(var item: String, var price: Int)

fun main(agrs: Array<String>) {    
    val p1 = Product1("Thinkpad", 5000)    
    val p2 = Product1("Thinkpad", 5000)    
    println(p1==p2)    
    println(p1.equals(p2))
    val d1 = Product2("Thinkpad", 5000)    
    val d2 = Product2("Thinkpad", 5000)    
    println(d1==d2)    
    println(d1.equals(d2))
}
//false
//false
//true
//true

对象表达式

class Shop2{
    var address:Address2 ?= null
    fun addAddress(address2:Address2){
        this.address = address2
    }
}

fun Test3(){
    Shop2().addAddress(object:Address2("Kotlin test"){
        override fun print(){
            super.print()
        }
    })
}

工具类

//工具类
object DataUtil{
    fun<T> isEmpty(list:ArrayList<T>):Boolean{
        return list?.isEmpty()?:false
    }
}
fun testUtil(){
    val list = arrayListOf("12")
    println(DataUtil.isEmpty(list))
}