Android 项目目录介绍
kotlin 的特点
富有表现力且简洁: 可以使用更少的代码实现更多的功能。少编写样板代码。在使用 Kotlin 的专业开发者中,有 67% 的人反映其工作效率有所提高。
更安全的代码:Kotlin 有许多语言功能,可帮助避免 null 指针异常等常见编程错误。包含 Kotlin 代码的 Android 应用发生崩溃的可能性降低了 20%。
可互操作:可以在 Kotlin 代码中调用 Java 代码,或者在 Java 代码中调用 Kotlin 代码。Kotlin 可完全与 Java 编程语言互操作,因此可以根据需要在项目中添加任意数量的 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
语句
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 循环控制
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
}
}