Android 项目目录介绍

Android 项目目录介绍

kotlin 的特点

  • 富有表现力且简洁: 可以使用更少的代码实现更多的功能。少编写样板代码。在使用 Kotlin 的专业开发者中,有 67% 的人反映其工作效率有所提高。

  • 更安全的代码:Kotlin 有许多语言功能,可帮助避免 null 指针异常等常见编程错误。包含 Kotlin 代码的 Android 应用发生崩溃的可能性降低了 20%。

  • 可互操作:可以在 Kotlin 代码中调用 Java 代码,或者在 Java 代码中调用 Kotlin 代码。Kotlin 可完全与 Java 编程语言互操作,因此可以根据需要在项目中添加任意数量的 Kotlin 代码。

  • 结构化并发:Kotlin 协程让异步代码像阻塞代码一样易于使用。协程可大幅简化后台任务管理,例如网络调用、本地数据访问等任务的管理。

Kotlin 数据类型

Kotlin数据类型

Kotlin 数据类型

1.1 整型

// 1. 如何声明一个基础数据类型的变量,有哪些方式?
// 基础数据类型的整型默认数据类型均为Int,如果超过了Int的取值范围,则会推断为Long
val number = 100 // 编辑器会根据赋值【100】,推断变量number数据类型为Int

// 虽然没有明确指定变量bigNumber的数据类型,但是编辑器会根据赋值发现【8000000000】已经超过了Int的最大值
// 所以bigNumber的数据类型会升级为Long
val bigNumber = 8000000000

// 在赋值数字的后面加上L,会自动推断为Long类型
val longNumber = 20L

// 在变量后面加上:明确数据类型
val byteNumber: Byte = 1

1.2 浮点型

// 浮点类型
// 编辑器同样会根据赋值推断变量的类型
val doubleNumber: Double = 3.14159268888
val floatNumber: Float = 3.14159268888f // 尾部加f或F显式表示这是一个Float类型的浮点数
// 发现float保留到小数点第8位
println("doubleNumber:$doubleNumber") // 输出:doubleNumber:3.14159268888
println("floatNumber:$floatNumber") // 输出:floatNumber:3.1415927

1.3 字符类型

// 字符类型
// 字符类型的声明用单引号
val char: Char = '0'

1.4 布尔类型

// 布尔类型,使用Boolean来声明类型,只有两种值true/false
val isVisible: Boolean = false
val isVisible2 = true

1.5 字符串

// 字符串类型
val str: String = "1234567890" // 从0开始
// 字符串的取值
val strNumber2: Char = str[1]
// 字符串的模板表达式以$开始
println("The Result:$str")
println("Text length is ${str.length}")
// 字符串的拼接操作
println("I am " + 10 + " years old!")
// 字符转义
val helloWorld = "Hello,World!\n"
println("$helloWorld\nhow are you")

// helloWorld3要求它的字符串内容是json格式
val helloWorld3 = "{\"key\" : \"value\"}"
// 分界符,内部不需要转义,看起来更清爽
val helloWorld4 = """
    {"key" : "value"}
""".trimIndent()

数据类型间的转换

// 数据类型间的强制转换, toLong, toInt, toFloat, toDouble, toChar, toByte
val number100 = 100 // 声明一个整型number对象
println("转换成string:$number100")
println("转换成long:${number100.toLong()}")

数据运算

3.1 加减乘除

// 数据类型的加减乘除
val numberInt: Int = 3 / 2 // = 1.5
println("numberInt:$numberInt") // 输出1

// 整数的3除以小数2
val numberDouble: Double = 3 / 2.toDouble() // 输出1.5
println("numberDouble:$numberDouble")
println("乘法:" + numberInt * numberInt)
println("取余:" + 3 % 2)

3.2 位运算

// 位运算
val vip = true
val admin = false
// 与操作,要求两个条件都满足结果才会为true
val result = vip.and(admin) // false
// 或操作,只要有一个条件为true,结果就为true
val result2 = vip.or(admin)

// 无符号右移
// 0000 1000 ---> 0000 0010 = 2
val result3 = 8 ushr (2)
println("result:$result")
println("result2:$result2")
println("result3:$result3")

容器

1.数组

1.1 arrayOf() 数组
  • 初始化是必须指定数组的元素 不定长,可以是任意类型
// 1. 使用arrayOf创建数组,必须指定数组的元素,可以是任意类型
val arrayNumber: Array<Int> = arrayOf(1, 2, 3, 4)

// 集合中的元素可以是任意类型
// kotlin中的Any等于java中的Object
val arrayObjects: Array<Any?> = arrayOf(1, true, "2", Gson())
1.2 arrayOfNulls()
  • 必指定元素类型、指定数组长度
// 2. 使用arrayOfNulls创建空数组
// 创建一个指定大小的、所有元素都为空的数组,但必须指定集合中的元素类型
// ?代表集合中的元素可为null
val arrayOfNulls: Array<String?> = arrayOfNulls(5)
arrayOfNulls[0] = "element1"
arrayOfNulls[1] = "element2"
arrayOfNulls[2] = "element3"
arrayOfNulls[3] = "element4"
arrayOfNulls[4] = null
1.3 动态创建数组(不常用)
  • 利用 Array 的构造函数动态的创建
// 3. 利用array的构造函数动态创建数组
// 创建一个Array<String>并初始化为["0","1","4","9","16"]
// i = 0, 1, 2, 3, 4
// i * i = "0","1","4","9","16"
// 数组创建的时候,会循环5次,i就是数组的下标
// -> 右边的表达式的结果,就是数组中当前的下标
val asc: Array<String> = Array(5) { i -> (i * i).toString() }
1.4 字节数组
// 4. 字节数组
val bytes = ByteArray(5)
bytes[0] = 1
1.5 使用 IntArray 创建整型数组
// 5. 使用IntArray创建整型的数据数组
// 1. 创建一个长度为5的空的IntArray
// Byte、Short、Int、Long、Float、Double、Boolean、Char
val ints = IntArray(5)
ints[0] = 1

// 3. 创建一个长度为5的IntArray并且里面每个元素都为100
val intArr3 = IntArray(5) { 100 }

// 4. 注意这里it是它索引下标值,所以这是创建一个长度为5的IntArray[0, 2, 4, 6, 8]
val intArr4 = IntArray(5) { it * 2 } // it,lambda表达式专有变量,这里指的是数组的下标
val intArr5 = IntArray(5) { i -> i * 2 } // 与上方的作用一样,但是上方的写法更加简洁

1.6 数组循环遍历
// 数组如何进行for循环遍历
// 依次取出数组中的元素,用for-in的形式
for (item in intArr4) {
    println(item)
}

// 根据下标再取出对应位置的元素
// for-in
for (i in intArr4.indices) {
    println(i.toString() + "->" + intArr4[i])
}

// 同时遍历下标和元素
for ((index, item) in intArr4.withIndex()) {
    println("$index -> $item")
}

// forEach会依次回调我们数组中的元素
intArr4.forEach {
    println("forEach:$it") // it代表的是数组的元素
}

// forEach增强版,会依次回调给我们数组中的下标和元素
intArr4.forEachIndexed { index, item ->
    println("$index -> $item")
}

2.集合

  • List:是一个有序列表,可通过索引(下标)访问元素。元素可以在 list 中出现多次、元素可重复。

  • Set:是元素唯一的集合。一般来说 set 中元素的顺序并不重要、无序集合。

  • Map:(字典)是一组键值对。键是唯一的,每个键都刚好映射到一个值,值可以重复。

列表

2.1 列表的创建方式
  • 2.1.1 mutableList<>() 可变列表
// 列表的创建方式——可变列表
  val arrayString = mutableListOf<String>()
  arrayString.add("1")
  arrayString.add("2")
  arrayString.add("3")
  arrayString.add("4")
  arrayString.add(3, "3")

  val arrayString2 = mutableListOf("1", "2", "3", "3")
  arrayString2.add("4")
  • 2.1.2 listOf<>() 不可变列表 必须指定元素类型,必须初始化数据元素
// 列表的创建方式——不可变列表
// 必须指定元素类型
// 必须指定初始化数据元素 不可变
val arrayInt = listOf(1, 2, 3)
//  arrayInt.add
//  arrayInt.remove
2.2 map 字典创建
  • 2.2.1 mutableMapOf<>() 可变字典
// map字典的创建——可变字典
// (字典)是一组键值对。键是唯一的,每个键都刚好映射到一个值,值可以重复。
val array = arrayMapOf(Pair("key", "value"))
val arrayMap = mutableMapOf<String, String>()
arrayMap["1"] = "1"
arrayMap["2"] = "2"
arrayMap["3"] = "3"
arrayMap["3"] = "4" // 此时,会覆盖上面的记录

// map字典的创建——使用Pair指定集合中初始化的元素
val arrayMap2 = mutableMapOf(Pair("key", "value"))
  • 2.2.2 mapOf<>() 不可变字典 不可动态添加删除元素
// map字典的创建——不可变字典,不可动态添加、删除元素
val arrayMap3 = mapOf(Pair("key", "value"))
val arrayMap4 = mapOf<String, String>()
2.3 Set 集合创建
  • 2.3.1 mutableSetOf<>() 可变集合元素,唯一
// set集合的创建——可变集合,元素唯一
val set = mutableSetOf<Int>()
set.add(1)
set.add(2)
set.add(3)
set.add(3) // 添加不进去
for (item in set) {
    println(item)
}

val set2 = mutableSetOf(1, 2, 3)
set2.add(1)
set2.add(2)
set2.forEach {
    println(it)
}
  • 2.3.2 setOf<>() 不可变
// set集合的创建——不可变集合,元素唯一
val set3 = setOf(1, 2, 3)
// set3.add
2.4 集合的操作 同样适用与 map,set,list
// 下面的方法同样适用于set,map,list
val arrayExamples = mutableListOf("1", "2", "3", "4")
println("isEmpty:${arrayExamples.isEmpty()}")
println("contains:${arrayExamples.contains("6")}")
println("containsAll:${arrayExamples.containsAll(listOf("1", "2"))}")
println("get:${arrayExamples[0]}")
println("indexOf:${arrayExamples.indexOf("6")}") // 判断元素在集合中的下标位置
println("lastIndexOf:${arrayExamples.lastIndexOf("5")}") // 判断元素在集合中的下标位置
val iterator = arrayExamples.iterator()
iterator.forEach {
    println("it:$it")
}
//    arrayExamples.clear() // 集合中的元素被清除
println("length:${arrayExamples.size}")
arrayExamples[0] = "0" // 修改下标对应的元素,index不能超过集合size的大小
arrayExamples.add("7") // 指定位置添加元素
arrayExamples.removeAt(0)

2.5 变换操作
val numbers = mutableListOf(1, 2, 3, 4)
numbers.reverse()
numbers.forEach {
    println("reverse:$it")
}

numbers.shuffle() // 随机排列元素
numbers.forEach {
    println("shuffle:$it")
}

numbers.sort() // 排序,从小到大排序
numbers.forEach {
    println("sort:$it")
}

numbers.sortDescending() // 排序,从大到小排序
numbers.forEach {
    println("sortDescending:$it")
}

Kotlin 方法与 Lambda 表达式

1. kotlin 的方法

1.1 方法声明

1.1.1 成员方法
  • 成员方法需要构建实列对象,才能访问成员方法
//成员方法
class Person{
    fun test(){
        println("Person test方法")
    }
}

fun main() {
    //成员方法需要构建实列对象,才能访问成员方法
    //示例对象的构建只需要在类名后面加上() !!!不需要new
    Person().test()
}
1.1.2 类方法
  • 当想要在 class 声明的类里面,想要定义一个静态方法的话使用伴生类
//成员方法
class Person{
    //伴生类
    companion object{
        fun test2(){
            println("伴生类的方法")
        }
    }
}

fun main() {
    //伴生类的方法调用
    Person.test2()
}
  • 静态类:如果我们想实现一个工具 util 时,可以借助关键字 object 创建一个静态类
//静态类
object NumUtil{
    fun plus(num:Int):Int{
        return num+1
    }
}

fun main() {
    //静态类方法调用,无须构建实例
    val n = NumUtil.plus(0)
    println("静态类方法 $n")
}
  • 全局静态: 直接新建一个 Kotlin file 然后定义一些常量、方法。
1.1.3 单表达式方法
//单表达式方法
fun double(x:Int):Int = x*2

fun main() {
    val double = double(2)
    println("单表达式方法 $double")
}

// 当返回值类型可由编译器推断时,显式声明返回类型是可选的:
fun double(x: Int) = x * 2

1.2 方法参数

1.2.1 默认参数
//2.1默认参数
//方法参数可以有默认值,当省略相应的参数时使用默认值。与其Java相比,这可以减少重载数量:
fun read(offset:Int=0,start:Int){
    println("offset $offset, start $start")
}

//函数调用
read(8,1)
1.2.2 具名参数

//bar: Int = 0 默认值为0
//baz: Int 无默认值
//第三个参数是一个方法,参数名为 qux 如果参数的类型是() ,说明参数是一个方法类型
//方法参数的返回值使用 ->Unit(无返回值)  ->String (返回值的类型是String)
fun foo(bar: Int = 0, baz: Int, qux: () -> String) {
    val qux1 = qux()
    println(qux1)
}


//函数调用
read(start = 3) //如果一个无默认值的参数在默认值参数后,该默认值只能通过使用具名参数调用该方法
foo(1,2 ,qux={
    //方法体里面的最后一行,就是该方法的返回值
    val res: Int = 3 * 4
    "res $res,括号内使用具名参数,传递action参数"
})
//当且仅当最后的参数是一个方法时才可以写在花括号外面
foo(baz=1){
    "括号外传递action参数"
}

1.2.3 可变数量的参数
2.3可变数量参数
fun append(vararg str:Char,num:Int):String {
    val res = StringBuffer()
    str.forEach {
        res.append(it)
    }
    return res.toString()
}

//函数调用
val append = append('1', '2', '3', 'a',num = 1)
println("append 可变数量参数 $append") // 输出:append 可变数量参数 123a

val world = charArrayOf('w', 'o', 'r', 'l', 'd')
val result = append('h', 'e', 'l', 'l', 'o',' ', *world,num = 1) //*world,依次添加world字符数组中的元素
println("append 可变数量参数 $result")

1.3 方法作用域

1.3.1 局部方法
  • 一个方法在另一个方法内部
  • 局部方法可以访问外部方法(即闭包)的局部变量
fun magic(): Int {
    //foo是局部方法
    fun foo(v: Int): Int {
        return v * v
    }

    val v1 = (0..100).random()
    return foo(v1)
}

2.Lambda 表达式

2.1 Lambda 表达式的特点

  • 是匿名方法
  • 可以作为参数传递给方法

2.2 Lambda 语法

无参数的 Lambda 表达式
// val/var 变量名 = {操作代码}

val sum = {
    println("无参数的Lambda表达式")
    1 + 2
}

//调用Lambda表达式
val result = sum()
println("无参数的Lambda表达式 $result")
有参数
// val/var 变量名:(参数类型,参数类型....) -> 返回的类型={参数1,参数2...... -> 操作参数的代码}
// 此种写法:即表达式的返回值类型会根据操作的代码自推导出来。
// val/var 变量名 = { 参数1 : 类型,参数2 : 类型, ... -> 操作参数的代码 }

val sum2: (Int, Int) -> Int = { a, b ->
    println("有参数的Lambda表达式")
    a + b
}

//调用Lambda表达式
val result2 = sum2(1, 2)
println("有参数的Lambda表达式 $result2")

2.3 Lambda 实践

//array int数组
//action方法,两个Int 参数,返回值是Int
fun change(array:Array<Int>,action:(index:Int,element:Int)->Int){
    for(index in array.indices){ //indices是数组下标
        val newValue = action(index,array[index])
        array[index] = newValue
        print("${array[index]} ")
    }
    println()
}

// 调用Lambda表达式
val number:Array<Int> = arrayOf(1,2,3,4)
change(number){ index, element ->
    index * element //方法体最后一句是return
}

2.3.1 隐式参数 it
  • it 并不是 Kotlin 中的一个关键字(保留字)

  • it 是在当一个高阶方法中 Lambda 表达式的参数只有一个的时候可以使用 it 来使用此参数

  • it 可表示为单个参数的隐式名称,是 Kotlin 语言约定的

// 调用时
number.forEach {
    print("$it ")
}
println()

// 多个参数就指明参数名类型

//forEachIndexed 参数是下标和元素
number.forEachIndexed{index: Int, element: Int ->
    println("forEachIndexed $index : $element")
}
//显示调用
/*number.forEachIndexed(action = {index: Int, element: Int ->
    println("forEachIndexed $index : $element")
})*/

2.3.2 下划线_
  • 在使用 Lambda 表达式的时候,可以用下划线(_)表示未使用的参数,表示不处理这个参数
val map = mapOf("key1" to "1", "key2" to "2", "key3" to "3")
map.forEach { (key, value) ->
    println("$key \t $value")
}

// 不需要key的时候
map.forEach { (_, value) ->
    println(value)
}

Kotlin 条件控制

  • Tips:Kotlin 中没有 switch-case 语句

Kotlin 条件控制

1.if 表达式

1.1 带返回值 if 表达式

fun maxOf(a:Int,b:Int):Int{ //比较两个值的大小
    if(a>b){
        return a
    }else{
        return b
    }
}

1.2 if 表达式替代三目运算符

fun maxOf2(a:Int,b:Int):Int{ //maxOf简写版
    return if (a > b) a else b
}

1.3 多级 if 表达式

fun eval(number: Number) {
    if (number is Int) {
        println("this is int number")
    } else if (number is Double) {
        println("this is double number")
    } else if (number is Byte) {
        println("this is byte number")
    } else if (number is Short) {
        println("this is Short number")
    } else {
        throw IllegalArgumentException("invalid argument")
    }
}

2.when 表达式

  • 代替 java 中的 switch case

  • when 将它的参数与所有的分支条件顺序比较,直到某个分支满足条件

  • 分支条件可以是 if 语句,数据类型,具体值

  • 如果不提供参数即 when(){…},所有的分支条件都是简单的布尔表达式

fun eval2(number: Any):String = when(number){
    1 -> "one"
    "hello" -> "hello word"
    is Int -> "int"
    is Double,Float -> "Double 或 Float" 多个分支条件放在一起,用逗号分隔
    is String -> {
        println("多行when")
        "String"
    }

    else  -> "invalid number"
}

3.when 表达式的功能增强

  • kotlin1.3 版本后 when(value) value 可以动态赋值,如方法的返回结果
fun eval3() :String = when (val value = getValue()) {
       //when表达式条件直接是一个表达式,并用value保存了返回值, 实际上相当于把外部那一行缩进来写
        is Int -> "This is Int Type, value is $value".apply(::println)
        is String -> "This is String Type, value is $value".apply(::println)
        is Double -> "This is Double Type, value is $value".apply(::println)
        is Float -> "This is Float Type, value is $value".apply(::println)
        else -> "unknown type".apply(::println)
}

fun getValue(): Any {
    return 100F
}

4.使用 when 表达式替代 if 表达式

  • 主函数调用
fun main() {
    //1.if
    //1.1带返回值 if 表达式
    println("maxOf ${maxOf(3,1)}")
    //1.3 多级 if 表达式
    println("eval ${eval(1.22)} \n")


    //2.when 表达式   (代替java中的switch case)
    println("eval ${eval2(99f)}")

    //3.when 表达式的功能增强
    eval3()
}

Kotlin 循环控制

Kotlin 循环控制

1.for 循环

//for item in elements  elements可以是数组、集合
//1.1 for-in
println("for-in")
for(item in items){
    print("$item ")
}
//1.2 forEach
println("\nforEach")
items.forEach{
    print("$it ")
}
//1.3 forEachIndexed
println("\nforEachIndexed")
items.forEachIndexed{index, item ->
    print("$index:$item   ")
}

2.while 和 do-while 循环

//2.while 和 do-while
//2.1 while 先判断再循环
println("\n\nwhile")
var index = 0
while(index <items.size){
    print("$index:${items[index++]}  ")
}
//2.2 do-while 先执行一次循环体,再判断循环
index = 0
println("\ndo-while")
do{
    print("$index:${items[index++]}  ")
}while(index < items.size)

3.迭代区间和数列 常用

//遍历区间,注意Kotlin的区间的包含或是闭合的
println("\n\n遍历区间")
for (i in 1..10) { //[1,10]
    print("$i ")
}
//for in-until 前闭后开
println("\nfor in-until")
for (i in 1 until 10) { //[1,10)
    print("$i ")
}
//for in downTo
println("\nfor in downTo")
for (i in 10 downTo 1) { //downTo 倒序遍历
    print("$i ")
}
//for in downTo step
println("\nfor in step")
for (i in 10 downTo 1 step 3) { //倒序 步长为3
    print("$i ")
}
//遍历数组时或list
println("\nindices")
val array = arrayOf(1,2,3)
for (i in array.indices) {//遍历索引
    print(" "+array[i])
}
println("\nwithIndex方法")
for ((index, value) in array.withIndex()) {
    print(" $index:$value   ")
}
println("\n\n")

4.循环中的 break 与 continue

//4.break continue
for (i in 1..12) {
    if (i % 2 == 0) continue // 如果 i 能整除于 2,跳出本次循环,进入下一个循环
    for (j in 1..12) {
        if (j > 5) break // 如果 j 小于 10 ,终止循环。
        print("$j ")
    }
    println()
}

泛型

1.泛型接口/类(泛型类型)

fun main() {
    //1.1 泛型接口
    val drinkApple = DrinkApple()
    drinkApple.drink("apple")
    //1.2 泛型类
    val blueColor = BlueColor("blue")
    blueColor.printColor()
}

//1.1泛型接口
interface Drink<T> {
    fun drink(t : T)
}
//接口实现
class DrinkApple : Drink<String>{
    override fun drink(t: String) {
        println("Drink $t")
    }
}


//1.2 泛型类
abstract class Color<T>(val t:T){ //t是成员变量
    abstract fun printColor()
}
class BlueColor(val color:String) : Color<String>(color){
    override fun printColor() {
        println("color is $color")
    }

}

2.泛型字段

  • 类或者方法入参指定的类型是 T
interface Drink<T> {
    fun drink(t : T) //t泛型字段
}

abstract class Color<T>(val t:T){ //t是成员变量 t泛型字段
    abstract fun printColor()
}

3.泛型方法

  • json 序列化的时候使用

  • 类型参数要放在方法名的前面

fun<T> fromJson(json:String , tClass:Class<T>) : T?{ //T?返回值可空(应对json为空的时候)
    //声明一个实列,可能会抛出异常(IllegalAccessException, InstantiationException;) 要显式声明类型 T?
    val instance:T? = tClass.newInstance()
    return instance
}

fun main() {
    //3.泛型方法
    fromJson<String>("{}",String::class.java) //class参数 String::class.java
}

4.泛型约束

  • 泛型约束指定泛型的类型范围
//4.泛型约束 (常见)
//约束写法1
// T : xObject  所传递的类型T必须满足是xObject的子类 或xObject类
fun<T : JSONObject> fromJson2(json:String , tClass:Class<T>) : T?{ //T?返回值可空(应对json为空的时候)
    //声明一个实列,可能会抛出异常(IllegalAccessException, InstantiationException;) 要显式声明类型 T?
    val instance:T? = tClass.newInstance()
    return instance
}
//约束写法2
//所传递的类型T必须同时满足 where 子句的所有条件
//where T:类x,T:接口x , T必须满足类x或类x的子类,  同时T必须实现 接口x
fun<T> fromJson3(json:String , tClass:Class<T>) : T? where T:JSONObject,T:Comparable<T>{ //T?返回值可空(应对json为空的时候)
    //声明一个实列,可能会抛出异常(IllegalAccessException, InstantiationException;) 要显式声明类型 T?
    val instance:T? = tClass.newInstance()
    return instance
}
class User : JSONObject(),Comparable<User>{
    override fun compareTo(other: User): Int {
        TODO("Not yet implemented")
    }

}

// 主函数调用

fun main() {
//4.泛型约束
fromJson2<JSONObject>("{}",JSONObject::class.java)
//4.2多种约束
fromJson3<User>("{}",User::class.java)
}

5.泛型中的 out 与 in

5.1 out 约束泛型参数的类型上限

//5.泛型中的out与in
open class Animal

class CatAnimal : Animal()
open class DogAnimal : Animal() //继承Animal
class whiteDogAnimal : DogAnimal()

fun animalFun(){
    val animal:Animal = DogAnimal()
    //5.1 out约束泛型参数的类型上限
    //不能做级别类型的类型强转
    // val animalList:ArrayList<Animal> = ArrayList<DogAnimal>() 报错类型错误
    //out  泛型参数的类型 允许传入T,以及T的子类
    //使用处使用out关键字声明——泛型上限
    val animalList:ArrayList<out Animal> = ArrayList<DogAnimal>()
    //在定义处使用out关键字声明
    val animalList1:ArrayList<Animal> = ArrayList<DogAnimal>()


}
//在定义处使用out关键字声明,允许传入的泛型参数可以是T以及T的子类
class ArrayList<out T>{

}

5.2in 约束泛型参数的类型下限

fun animalFun(){
    //5.2in约束泛型参数的类型下限 允许传入的类型泛型参数可以是T以及T的父类
    //val animalList3:ArrayList<DogAnimal> = ArrayList<Animal>() //报错类型错误
    //使用处使用in关键字声明——泛型下限
    val animalList3:ArrayList<in DogAnimal> = ArrayList<Animal>()
    在定义处使用out关键字声明
    val animalList4:ArrayList<DogAnimal> = ArrayList<Animal>()

}

//5.2in约束泛型参数的类型下限
class ArrayList<in T>{

}

kotlin 扩展函数

扩展方法

  • 扩展方法的原型
fun String.lastChar(): Char = this.get(this.length-1)

2.扩展方法的使用

2.1 在 Kotlin 中使用

fun main() {
    Jump().test()
    Jump().doubleJump()
}

class Jump{
    fun test(){}
}
//扩展函数的定义,就是在方法的前面加上类前缀
//针对无法直接修改类的时候,如想要修改一个jar包种的类
fun Jump.doubleJump():String{
    return "Jump.doubleJump()"
}

2.2 在 Java 中使用

public class KtExtensions {
    public static void main(String[] args) {
        KTExtensionsKt.doubleJump(new Jump());
    }
}S

3.原理解析:Kotlin 扩展函数是怎么实现的

  • AS 中Tools —> kotlin ----> show kotlin byteCode
public final class KTExtensionsKt {
   public static final void main() {
      (new Jump()).test();
      doubleJump(new Jump());
   }

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

   @NotNull
   public static final String doubleJump(@NotNull Jump $this$doubleJump) {
      Intrinsics.checkNotNullParameter($this$doubleJump, "$this$doubleJump");
      return "Jump.doubleJump()";
   }
}
  • 通过反编译出的 java 代码
  • 当在 java 中调用 kotlin 扩展方法时需要传入一个所扩展类的实例对象

4.泛型扩展方法

fun <T> MutableList<T>.swap(index1:Int , index2: Int){
    val temp = this[index1]
    this[index1] = this[index2]
    this[index2] = temp
}

// 主函数调用

fun main() {
    //4.泛型扩展方法
    val list = mutableListOf(1,2,3)
    list.swap(0,2)
    println("泛型扩展方法 $list")
}

5.扩展属性

  • 扩展属性提供了一种方法能通过属性语法进行访问的 API 来扩展。
//5.扩展属性
//对String类添加一个lastChar属性 (在kotlin里任何字段都有get set方法)
val String.lastChar:Char get() = this.get(this.length - 1)

// 主函数调用
fun main(){
//5.扩展属性
val str = "evening"
val strLastChar = str.lastChar
println("\nlastChar: $strLastChar")
}

6.为伴生对象添加扩展

class Eat {
    companion object {}
}
fun Eat.Companion.print(str: String) {
    println("Eat.Companion"+str)
}
// 主函数调用
fun main() {
    //6.为伴生对象添加扩展
    Eat.print("伴生对象添加扩展")
}

7.Kotlin 中常用的扩展

7.1 let 扩展

  • let 扩展函数的实际上是一个作用域函数

    • 当你需要去定义一个变量在一个特定的作用域范围内,那么 let 函数是一个不错的选择;
    • let 函数另一个作用就是可以避免写一些判断 null 的操作。
//7.1  let扩展 类名后面加上? 代表参数可能为空,使用的时候 注意判空
fun testLet(str: String?){
/*    str.let {//it:String?
        val str2 = "morning"
        println(str2 + it)
    }*/

    //判空用法,当str为空时不会触发闭包里面的逻辑
    str?.let{
        val str2 = "morning"
        println("$str2  $it")
    }
}
// 主函数调用
//7.1  let扩展
testLet("ddd")

7.2 run 扩展

  • run 函数只接收一个 lambda 函数为参数,以闭包形式返回,返回值为最后一行的值或者指定的 return 的表达式,在 run 函数中可以直接访问实例的公有属性和方法
//7.2 run扩展
//在run函数中可以**直接访问实例的公有属性和方法**
fun testRun(jump: Jump) : String{
    jump.run {
        test() //jump.test()
        return "run函数"
    }
}

// 主函数调用
fun main(){
//7.2 run扩展
val j = Jump()
println(testRun(j))
}

7.3 apply 扩展

  • apply 函数的作用是:调用某对象的 apply 函数,在函数范围内,可以任意调用该对象的任意方法,并返回该对象。

  • 从结构上来看 apply 函数和 run 函数很像,唯一不同点就是它们各自返回的值不一样 run 函数是以闭包形式返回最后一行代码的值,而 apply 函数的返回的是传入对象的本身

//7.3 apply扩展
fun testApply() {
    arrayListOf<String>().apply {
        add("111")
        add("22222")
    }.let {
        println(it)
    }
}

// 主函数调用
fun main(){
//7.3 apply扩展
testApply()
}

案例:使用 Kotlin 扩展为控件绑定监听器减少模板代码

class MainActivity : AppCompatActivity() {
		。
		。
		。
		。

        //绑定点击事件
        R.id.nav_view.onClick(this){ //click函数
            println("nav_view onClick")
        }
    }
}

//扩展函数 能够直接根据一个id为view绑定一个监听事件
fun Int.onClick(activity: Activity , click:()->Unit){
    activity.findViewById<View>(this).setOnClickListener{
        println("onClick")
        click()
    }
}

kotlin 一次四则运算计算器

package com.example.firstapp.lesson

import java.lang.Exception

/**
 *@author: hairly owl
 *@time:2021/10/13 21:22
 *@version: 1.00
 *@description: 一次四则运算计算机器
 */

fun main() {
    while(true){
        println("==========请输入你的表达式==========")
        //接受控制台输入数据
        val input:String? = readLine() //判空的校验
        try {
            input?.let {
                val res = calculate(it)
                println("${input} = ${res}")
                println("是否继续使用(y/n)")
                val cmd = readLine()
                cmd?.let{
                    if(it.equals("n")){
                        System.exit(-1) //强制退出程序
                    }else{
                        //继续使用

                    }
                }
            }
        }catch (ex:Exception){
            ex.printStackTrace() //打印异常
        }
    }
}

//四则运算函数
fun calculate(input: String): String {
    if(input.contains("+")){ //加法
        //数据处理
        val nums = input.trim().split("+") //去掉空格 分割操作符左右
        return operate(nums[0].toDouble(),nums[1].toDouble(),"+").toString()

    }else if (input.contains("-")){ //减法
        val nums = input.trim().split("-")
        return operate(nums[0].toDouble(),nums[1].toDouble(),"-").toString()

    }else if (input.contains("*")){ //减法
        val nums = input.trim().split("*")
        return operate(nums[0].toDouble(),nums[1].toDouble(),"*").toString()

    }else if (input.contains("/")){ //减法
        val nums = input.trim().split("/")
        return operate(nums[0].toDouble(),nums[1].toDouble(),"/").toString()
    }else{
        return "error: 您输入的表达式有误"
    }
}

//计算函数
fun operate(num1: Double, num2: Double, operator: String): Double {
    return when(operator){ //kotlin中的when代替 java中的switch-case
        "+" -> num1 + num2
        "-" -> num1 - num2
        "*" -> num1 * num2
        "/" -> num1 / num2
        else -> 0.0
    }
}

参考资料