第一章 kotlin 前提
1.1 kotlin与JVM虚拟机关系
[Kotlin/Java/Groovy] → 编译环节 → 产生字节码 → JVM产生指令 → 系统命令式执行
1.2 kotlin的意义
- 各个语言的核心集合
- 可以作为全栈语言
第二章 kotlin 基础篇
2.1 hello word 输出
fun main(){
println("hello world")
}
2.2 Kotlin内置数据类型(引用类型)
- 字符类型:
- String(字符串)
- Char(单字符)
- 数值类型:
- Int(整型)
- Float(浮点数)
- Double(小数)
- 布尔类型
- Boolean True/False
- 集合类型
- List(列表元素)
- Set(无重复的集合元素)
- Map(键值对)
2.3 声明变量
-
格式1: var 变量名:数据类型 [= 初始值]
作用: 可以读写
fun main(){ var name:String = "demo" println(name) }
-
格式2: val 变量名:数值类型 [= 初始值]
作用: 只能读
fun main(){ val name:String = "demo" // name = "demo1" --> 报错 println(name) }
2.4 const val、val、var 声明区别
- const val 定义在函数外,编译时常量
- val 只读类型
- var 读写类型
2.5 查看字节码和反编译的java代码
-
查看字节码
-
反编译java代码
2.6 Range表达式: ..
-
格式: 初始值..结束值
作用: 从初始值到结束值
fun main() { var num: Int = 59 if (num in 0..59) { println("不及格") } else { println("及格") } }
2.7 When表达式: when
-
格式: val 变量名:变量类型 = when(入参值){ 匹配入参值1 → 返回信息 … else → 返回信息}
作用: 一值多匹配结果
fun main() { var week: Int = 1 var result: Any = when (week % 7) { 0 -> "星期天" 1 -> "星期一" 2 -> "星期二" 3 -> "星期三" 4 -> "星期四" 5 -> "星期五" 6 -> "星期六" else -> "没有匹配到" } println(result) }
2.8 String模版: 输出模版
-
格式: “{变量名}” 或 ”变量名”
作用: 简化模版格式,其中 ”$变量名” 只能用于无文本紧密连接的情况
fun main() { val name: String = "zhangsan" val age: Int = 18 println("姓名:${name},年龄:$age") }
2.9 控制台键入值: 输入内容
-
格式: readline()
作用: 读取输入的一行内容
fun main(args: Array<String>) { print("请输入内容: ") val content: String? = readLine() println("你所输入的内容为:${content}") }
-
格式: val input:Scanner = Scanner(System.
in
)作用: 声明Java版本的读取
import java.util.Scanner fun main(args: Array<String>) { val input: Scanner = Scanner(System.`in`) print("请输入内容:") val content: String = input.nextLine() println("你所输入的内容为:${content}") }
2.10 常规函数
-
参数中不含默认的函数
格式: 函数修饰符 fun 函数名(参数名1:参数类型1…参数名n:参数类型n):返回数据类型 { 代码段 }
注意: 函数修饰符默认为public
fun main() { var result = add(2, 3) println("2 + 3 = $result") } public fun add(x: Int, y: Int): Int { return x + y }
-
参数中含默认值的函数
格式: 函数修饰符 fun 函数名(参数名1:参数类型1,参数名2:参数类型2=默认值…参数名n:参数类型n):返回数据类型 { 代码段 }
注意: 默认值可以没有顺序,但传参赋值一定是从左到右
fun main() { var result = add(3) println(result) } public fun add(x: Int = 2, y: Int = 4): Int { return x + y }
-
具名参数的函数
格式[调用]: val 变量名[:变量类型] = 函数名(参数名1=参数值1…参数名n=参数值n)
注意: 调用时,不需要从左到右依次赋值
fun main() { var result = add(y = 3) println(result) } public fun add(x: Int = 2, y: Int): Int { return x + y }
2.11 空返回: Unit
-
返回类型可以为空,空时可以输出内容[ kotlin.Unit ]
注意: 不加返回值类型,默认为Unit
fun main() { method() method1() //输出 kotlin.Unit var result = method2() println(result) } //默认为Unit, 可加入return语句,但必须为Unit类型 fun method() { return println() } //返回类型Unit, 可加入return语句,但必须为Unit类型 fun method1(): Unit { return println() } fun method2(): Unit { println() }
2.12 无法正常返回: Nothing
-
一般正常返回的值,都是有返回类型的,默认都是为空返回. 但存在无法返回的情况,例如抛出异常等,所以就存在了Nothing
注意: Nothing是所有类型的子类
fun main() { throwError() } fun throwError(): Nothing { // throw 和 TODO 都是可以抛出异常的 //TODO("主动抛出异常") throw Exception("主动抛出异常") }
2.13 反引号: `
-
用途: 1. 用做函数的名称; 2. 在调用其他语言过程中含有Kotlin语法的关键字(经常); 3. 具体功能的转译
public class JavaClass { public void in(String content) { System.out.println("输出的内容为:" + content); } }
fun main(args: Array<String>) { val javaCode: JavaClass = JavaClass() javaCode.`in`("kotlin 传递给 java代码的内容") }
2.14 进阶函数
-
匿名函数
函数实现在方法之后,不需要显式声明调用
fun main(args: Array<String>) { val len: Int = "hello".count() println("hello的个数为${len}") val lenforL: Int = "hello".count { it == 'l' } println("hello中的l的个数为${lenforL}") }
-
函数的隐式返回: 函数不需要单独定义,在需要处直接声明实现
不带参数: 可直接使用声明的名称调用
fun main(args: Array<String>) { //函数的声明 val method: () -> String //函数的实现 method = { "这是返回的字符" } //函数的使用 println(method) }
带参数: 需要进行传递所需参数内容。在只有一个参数时,注意默认会有一个 it 关键字
fun main(args: Array<String>) { val add: (x: Int, y: Int, z: Int) -> Int = { x: Int, y: Int, z: Int -> x + y + z } println("1,2,3 三值只和为:${add(1, 2, 3)}") }
-
函数返回的lambda推导
在不确定返回值的情况下,可不用写返回类型,自动推导出返回值的类型
注意: 当返回值类型不止一种的时候,返回的类型则为Any
fun main(args: Array<String>) { var method = { x: String, y: Int -> "输入内容,字符串:${x},数值:${y}" } println(method("demo", 1)) }
-
函数中的参数为函数
参数为函数作为返回值,处理返回来的内容信息
fun main() { loginSQL("root", "123456") { code: Int, status: String, msg: String -> println("请求的结果如下:状态值:${code},状态:${status},提示信息:${msg}") } //其余写法 loginSQL("root", "123456", { code: Int, status: String, msg: String -> println("请求的结果如下:状态值:${code},状态:${status},提示信息:${msg}") }) loginSQL("root", "123456", Response = { code: Int, status: String, msg: String -> println("请求的结果如下:状态值:${code},状态:${status},提示信息:${msg}") }) } //模拟前端发送请求 public fun loginSQL(username: String, password: String, Response: (code: Int, status: String, msg: String) -> Unit) { if (username != null && password != null) { if (loginSQLAPI(username, password)) { Response(200, "ok", "数据库访问成功") } else { Response(500, "error", "数据库访问失败") } } else { TODO("用户名或者密码为空") } } //数据库的数据 const val name = "root" const val pwd = "123456" //后台接口API private fun loginSQLAPI(username: String, password: String): Boolean { return if (username == name && password == pwd) true else false }
2.15 内联模式: inline
-
作用对象: 存在函数中参数为函数的方法
优点: 1. 不会存在性能损耗; 2. 不存在对象的开辟
注意: 使用内联模式的函数,其调用的函数方法属性必须为public
fun main() { loginSQL("root", "123456") { code: Int, status: String, msg: String -> println("请求的结果如下:状态值:${code},状态:${status},提示信息:${msg}") } //其余写法 loginSQL("root", "123456", { code: Int, status: String, msg: String -> println("请求的结果如下:状态值:${code},状态:${status},提示信息:${msg}") }) loginSQL("root", "123456", Response = { code: Int, status: String, msg: String -> println("请求的结果如下:状态值:${code},状态:${status},提示信息:${msg}") }) } //模拟前端发送请求 public inline fun loginSQL(username: String, password: String, Response: (code: Int, status: String, msg: String) -> Unit) { if (username != null && password != null) { if (loginSQLAPI(username, password)) { Response(200, "ok", "数据库访问成功") } else { Response(500, "error", "数据库访问失败") } } else { TODO("用户名或者密码为空") } } //数据库的数据 const val name = "root" const val pwd = "123456" //后台接口API public fun loginSQLAPI(username: String, password: String): Boolean { return if (username == name && password == pwd) true else false }
2.16 函数类型引用: ::
-
作用对象: 存在函数中参数为函数的方法
优点: 可以将返回参数的函数进行显式的声明和实现
fun main() { login("root", "123456", ::processResponse) } fun processResponse(code: Int, status: String, msg: String) { println("访问结果信息:状态值:${code},状态:${status},信息提示:${msg}") } public inline fun login(name: String, pwd: String, Response: (code: Int, status: String, msg: String) -> Unit) { if (name == "root" && pwd == "123456") { Response(200, "ok", "访问成功") } else { Response(200, "error", "访问失败") } }
2.17 返回值为函数
-
将函数的返回值由类型改为函数,可双重调用,调取函数返回函数的值
fun main(args: Array<String>) { val subMethod: (age: Int) -> String = method("zhangsan") println(subMethod(19)) } inline fun method(name: String): (age: Int) -> String { println("你的名字是:${name}") return { "实际的年龄为:${it - 1}" } }
2.18 具名函数和匿名函数对比
-
区别: 具名函数可以将函数声明实现在其他地方,匿名函数必须在调用的时候实现
关联: 具名函数 == 函数类型引用 ; 匿名函数 == 函数中的参数为函数
fun main(args: Array<String>) { //匿名调用 method("zhangsan", 18) { println("实际年龄为:${it - 1}") } //具名调用 method("zhangsan", 18, ::optionImpl) } fun method(name: String, age: Int, option: (age: Int) -> Unit) { println("你的姓名为:${name},虚岁年龄为:${age}") return option(age) } fun optionImpl(age: Int): Unit { println("实际年龄为:${age - 1}") }
2.19 属性可空特性: ?
-
注意: 默认声明一般是为不空
fun main(args: Array<String>) { //不可空属性 var name: String = "demo" println(name) //可空属性 val num: Int? = null println(num) }
2.20 属性安全调用
-
可空类型的安全调用
格式: 属性名?.方法名()
作用: 通过判断属性名是否为空,从而判断是否进行执行属性名后的方法
fun main(args: Array<String>) { var name: String? = "demo" //属性名?.方法 ,当属性值不为空时执行后面的方法,属性值为空时不执行后面的方法 println("当前值为:${name?.capitalize()}") name = null println("改变后的值为:${name?.capitalize()}") }
-
let安全调用
格式: 属性名?.let{ 代码段 }
作用: 当属性名不为空时,执行后面的代码段,且返回最后一行的值
fun main(args: Array<String>) { var name: String? = "demo" val result1: String? = name?.let { it.capitalize() } println("当前值为:${result1}") name = null val result2: String? = name?.let { it.capitalize() } println("改变之后的值为:${result2}") }
-
非空断言
格式: 属性名!!.方法名()
注意: 断言的内容一定要事先知道预期的结果,因为方法是会执行,不论属性为什么值
fun main(args: Array<String>) { var name: String? = null //非空断言,属性值无论是什么都会执行后续的方法 println(name!!.capitalize()) //这里会报错,空指针异常 }
-
if判空
格式: if(属性名 [比较] 预设值) 操作
fun main(args: Array<String>) { var name: String? = null if (name == null) { println("当前的name值为空") } else { println("当前的name值不为空") } }
-
空合并
格式: 属性名?:为空时的值
fun main(args: Array<String>) { var name: String? = null val result: String = name ?: "null" println("当前的name值为:${name}") }
2.21 异常处理: try…catch
-
作用: 主要为了预防一些可见的异常和一些不可见的异常
fun main(args: Array<String>) { try { var info: String? = null checkNotNullException(info) } catch (e: Exception) { e.printStackTrace() } } fun checkNotNullException(value: String?) { value ?: throw ValueIsNullException() } public class ValueIsNullException : NullPointerException("空指针异常")
2.22 先决条件
-
作用: 为了判断属性是否为空
fun main(args: Array<String>) { var name: String? = null //为null时进行异常提示:java.lang.IllegalStateException: Required value was null. checkNotNull(name) //定义带有返回提示的异常信息:java.lang.IllegalStateException: 属性值不能为空 checkNotNull(name, lazyMessage = { "属性值不能为空" }) //当为false是抛出异常,为true正常执行:java.lang.IllegalStateException: Check failed. check(name?.let { true } ?: false) //带有返回提示的异常信息:java.lang.IllegalStateException: 属性值不能为空 check(name?.let { true } ?: false, lazyMessage = {"属性值不能为空"}) //同理 require和check相似,requireNotNull和checkNotNull相似 requireNotNull(name) requireNotNull(name, lazyMessage = { "属性值不能为空" }) require(name?.let { true } ?: false) require(name?.let { true } ?: false, lazyMessage = { "属性值不能为空" }) }
2.23 String类常用的方法
-
subString方法
用途: 分割字符串
fun main(args: Array<String>) { var str: String = "hello world" val subStr1: String? = str.substring(0..5) println("字符串0-5的字符为:${subStr1}") val subStr2: String? = str.substring(0, str.indexOf(' ')) println("字符串从头到第一个为空格的字符为:${subStr2}") val subStr3: String? = str.substring(0 until str.indexOf(' ')) println("字符串从头到第一个为空格的字符为:${subStr3}") }
-
split方法
用途: 分割字符串成若干子字符串数组
fun main(args: Array<String>) { var str: String = "hello world" var splitStr: List<String> = str.split(' ') println("当前分割结果为;${splitStr}") }
-
replace方法
用途: 替换字符中的部分内容
fun main(args: Array<String>) { var str: String = "hello world" var result: String = str.replace('o', 'e') println("替换后的结果为:${result}") }
-
foreach方法
用途: 用于循环某个内容
fun main(args: Array<String>) { var str: String = "hello world" print("循环输出的结果为: ") str.forEach { print("${it} ") } }
-
==和===比较
区别: == 用于值或者内容的比较; === 除了值或内容比较外,还有引用的比较
fun main(args: Array<String>) { var str1: String = "hello world" var str2: String = "hello world" // == 用于值或内容的比较,与java中的equals相同 println("str1 == str2 的结果为:${str1 == str2}") println("str1 == str2 的结果为:${str1.equals(str2)}") // === 用于引用比较 println("str1 === str2 的结果为:${str1 === str2}") }
2.24 类型转换
-
String类型 → Int类型
作用: 将String类型的值转化为Int类型的值
fun main(args: Array<String>) { val num: Int = "66".toInt() println(num) //转化失败将为null var num1: Int? = "66.6".toIntOrNull() println(num1) var num2: Int? = "99".toIntOrNull() println(num2) var num3: Int? = "66.6".toIntOrNull() println(num3 ?: "null值") }
-
Double类型 → Int类型
作用: 将Double类型的值转化为Int类型
import kotlin.math.roundToInt fun main(args: Array<String>) { // toInt()和roundToInt()四舍五入方式 println(65.13451234.toInt()) println(65.13451234.roundToInt()) println(65.612345.roundToInt()) }
-
Double类型 → String类型
作用: 将Double类型格式化String类型
fun main(args: Array<String>) { var r: String = "%.3f".format(65.13451234) println(r) }
2.25 内置函数
-
apply内置函数
特点: 入参默认含有this对象,返回对象本身类型
fun main(args: Array<String>) { var name: String = "demo" //apply入参默认含有this对象 var result: String = name.apply { println("你的名字为:${this.capitalize()}") } //apply返回对象本身 println("返回的结果为:${result}") }
-
let内置函数
特点: 入参默认含有it对象,返回最后一行的内容
fun main(args: Array<String>) { var name: String = "demo" //let入参默认含有it对象 var result: Unit = name.let { println("你的名字为:${it.capitalize()}") } //it返回代码块中最后一行内容 println("返回的结果为:${result}") }
-
run 内置函数
特点: 入参默认含有this对象,返回最后一行内容
用法: 与apply和run相同.在链式调用时需要一个接一个
fun main(args: Array<String>) { var name: String = "demo" //run入参默认含有this对象 var result: Unit = name.run { println("你的名字为:${this.capitalize()}") } //run返回代码块中最后一行内容 println("返回的结果为:${result}") }
-
with 内置函数
特点: 入参默认含有this对象,返回最后一行内容
用法: 与run不相同.在链式调用时,需要层层嵌套
fun main(args: Array<String>) { var name: String = "demo" //run入参默认含有this对象 var result = with(name, { println("你的名字为:${this}") }) //run返回代码块中最后一行内容 println("返回的结果为:${result}") }
-
also 内置函数
特点: 入参默认含有it对象,返回对象本身
fun main(args: Array<String>) { var name: String = "demo" //also入参默认含有it对象 var result = name.also { println("你的名字为:${it.capitalize()}") } //also返回对象本身 println("返回的结果为:${result}") }
-
takeif 内置函数
特点: 如果takeif内的返回值为true则返回对象,否则返回nul
fun main(args: Array<String>) { var name: String? = "demo" var result1 = name.takeIf { name?.let { true } ?: false } println("初始值takeif结果为:${result1}") name = null var result2 = name.takeIf { name?.let { true } ?: false } print("赋值为null后的结果为:${result2}") }
-
takeunless 内置函数
特点: 如果takeunless内的返回值为false则返回对象,否则返回null
关联: 与takeif相反
fun main(args: Array<String>) { var name: String? = "demo" var result1 = name.takeUnless { name?.let { false } ?: true } println("初始值takeif结果为:${result1}") name = null var result2 = name.takeUnless { name?.let { false } ?: true } print("赋值为null后的结果为:${result2}") }
2.26 List集合
-
长度不可变的List
定义即初始化,该List可通过相应的方法增加、删除元素
fun main(args: Array<String>) { val strs: List<String> = listOf("list1", "list2", "list3") //输出 println(strs) //下标访问 println(strs.get(0)) println(strs[1]) //防止越界操作 getOrElse当越界后返回{}内的值 println(strs.getOrElse(3) { "越界" }) //防止越界操作 getOrNull当越界之后返回null值,一般配合空合并操作 println(strs.getOrNull(4) ?: "越界") //添加元素 该方法为kotlin.collections println(strs.plusElement("listNew1")) //删除元素 该方法为kotlin.collections println(strs.minusElement("listNew1")) }
-
长度可变的List
定义可以初始化,该List可以直接增加、删除和修改元素
fun main(args: Array<String>) { val strs: MutableList<String> = mutableListOf("list1", "list2", "list3") //增加操作 默认增加在最后 strs.add("listNew1") println(strs) //删除操作 如何删除的元素存在则删除,否则返回原数组内容 strs.remove("list1") println(strs) //将不可变list集合转化为可变list集合 val strs1: List<String> = listOf("new1", "new2", "new3") val strs2: MutableList<String> = strs1.toMutableList() println(strs2) }
可变长度的List,在增加时可以通过 += 进行添加元素; 在删除时也可以通过 removeif 进行删除
fun main(args: Array<String>) { val strs: MutableList<String> = mutableListOf("list1", "list2", "list3") //增加操作 默认增加在最后 strs += "listNew1" println(strs) //删除操作 对每一个元素判断是否包含字段值,包含则删除,不包含则保留 strs.removeIf { it.contains("New") } println(strs) }
-
遍历List
遍历不可变和可变长度的List集合
fun main(args: Array<String>) { val strs: List<String> = listOf("new1", "new2", "new3") val strs1: MutableList<String> = strs.toMutableList() //遍历 List-不可变 和 MutableList-可变 相同 print("for循环的结果为:") for (item in strs1) { print("${item} ") } println() print("foreach循环的结果为:") strs1.forEach({ print("${it} ") }) println() print("含有下标的forEachIndexed循环结果为:") strs1.forEachIndexed({ index: Int, s: String -> print("下标为 ${index} 的值为 ${s} ;") }) println() }
2.27 解构过滤
-
通过对对象的解析,返回特定位置上的特定值
注意: 当不需要某个位置的元素时,可以通过 _ 进行忽略
fun main(args: Array<String>) { val strs: List<String> = listOf("value1", "value2", "value3") //对应位置的解构,不能过多的解析,否则就会报错 var (v1: String, _, v2: String?) = strs println("解析结果为:${v1},${v2}") // var (v1: String, _, _, v2: String?) = strs -- 报错,strs的list集合并没有第四个元素 }
2.28 Set集合
-
不可变的Set集合
与长度不可变的List相似,但Set集合元素无重复
fun main(args: Array<String>) { //Set集合元素不重复 val strs: Set<String> = setOf("set1", "set2", "set3", "set1") println(strs) //访问 下标访问 println(strs.elementAt(1)) //访问 elementAtOrElse,当位置上没有值时返回{}内的内容 var result1: String = strs.elementAtOrElse(3, { "该位置没有值" }) println(result1) //访问 elementAtOrNull,当位置上没有值时返回null 一般与空拼接结合使用 var result2: String = strs.elementAtOrNull(3) ?: "该位置没有值" println(result2) //增加元素 println(strs.plusElement("it")) //删除元素 println(strs.minusElement("it")) }
-
可变的Set集合
与长度可变的List相似,但Set集合元素无重复
fun main(args: Array<String>) { val strs: MutableSet<String> = mutableSetOf("set1", "set2", "set3", "set1") println(strs) //增加元素 strs += "setNew" println(strs) strs.add("setNew1") println(strs) //删除元素 strs -= "setNew" println(strs) strs.remove("setNew1") println(strs) }
2.29 List集合去重
-
解决List集合中含有重复的元素
fun main(args: Array<String>) { val strs: List<String> = listOf("list1", "list2", "list3", "list1") println("去重前的值:${strs}") //去重方法1: 转化为Set集合 val strsSet: Set<String> = strs.toSet() println("转化为Set集合去重后的结果:${strsSet}") //去重方法2:转化为Set集合,在转化为List集合 val strsNew: List<String> = strs.toSet().toList() println("先转化为Set集合,再转化为List集合去重后的结果:${strsNew}") //去重方法3:通过distinct()方法去重 val strsDistinct: List<String> = strs.distinct() println("通过Distinct()方法去重后的结果:${strsDistinct}") //等价方法 strs.toMutableSet().toList() }
2.30 数组
-
数组的类型
数组类型 赋值方法 IntArray intArrayOf DoubleArray doubleArrayOf LongArray longArrayOf ShortArray shortArrayOf ByteArray byteArrayOf FloatArray floatArrayOf BooleanArray booleanArrayOf Array arrayof -
单一类型的一类值的集合
fun main(args: Array<String>) { val intArray: IntArray = intArrayOf(1, 2, 3, 4, 5, 7, 6) println(intArray) //访问元素 println(intArray[0]) println(intArray.get(1)) //访问 elementAtOrElse,当位置上没有值时返回{}内的内容 var result1: Int = intArray.getOrElse(10, { -1 }) println(result1) //访问 elementAtOrNull,当位置上没有值时返回null 一般与空拼接结合使用 var result2: Int = intArray.getOrNull(10) ?: -1 println(result2) //List集合转为数组,只有数据类型内含有的才可以转化,但除了Arrya之外 val strs: List<Char> = listOf('1', '2', '3', '4') val strsToArray: CharArray = strs.toCharArray() println(strsToArray) }
2.31 Map集合
-
创建Map集合
参数格式: 类型1 to 类型2 或者 Pair(类型1,类型2)
fun main(args: Array<String>) { var map1: Map<String, Any> = mapOf<String, Any>("code" to 200, "status" to "ok", "data" to listOf<String>("value1", "value2")) var map2: Map<String, Any> = mapOf<String, Any>(Pair("code", 200), Pair("status", "ok"), Pair("data", listOf<String>("value1", "value2"))) }
-
访问Map集合
fun main(args: Array<String>) { var map1: Map<String, Any> = mapOf<String, Any>("code" to 200, "status" to "ok", "data" to listOf<String>("value1", "value2")) var map2: Map<String, Any> = mapOf<String, Any>(Pair("code", 200), Pair("status", "ok"), Pair("data", listOf<String>("value1", "value2"))) //访问Map集合 println(map1["code"]) println(map1["status"]) println(map1.get("data")) //访问字段 getOrDefault 当对象中没有该key值时就会返回后面的默认的value值,反之返回对象中的值 println(map1.getOrDefault("msg", "暂无此字段")) //访问字段 getOrElse 当对象中没有该key值时就会返回后面的默认的value值,反之返回对象中的值 println(map1.getOrElse("msg", { "暂无此字段" })) }
-
遍历Map集合
fun main(args: Array<String>) { var map1: Map<String, Any> = mapOf<String, Any>("code" to 200, "status" to "ok", "data" to listOf<String>("value1", "value2")) var map2: Map<String, Any> = mapOf<String, Any>(Pair("code", 200), Pair("status", "ok"), Pair("data", listOf<String>("value1", "value2"))) map1.forEach { t, u -> println("集合的key为:${t},value为:${u}") } println() map1.forEach { (key: String, value: Any) -> println("集合的key为:${key},value为:${value}") } println() for (item: Map.Entry<String, Any> in map1) { println("集合的key为:${item.key},value为:${item.value}") } }
-
可变Map集合操作
fun main(args: Array<String>) { var map: MutableMap<String, Any> = mutableMapOf<String, Any>(Pair("code", 200), Pair("status", "ok"), Pair("data", listOf<String>("value1", "value2"))) //添加字段值 map += Pair<String, Any>("msg", "操作成功") println(map) map["field1"] = "value1" println(map) //获取或者存入值 getOrPut val result = map.getOrPut("msg", { "暂无此字段的值" }) println(result) }
第三章 kotlin进阶篇
3.1 类: class
-
类与 filed 关键字
注意: kotlin中的属性在经过转译之后,会将属性私有化,会提供对应的set或get方法.根据kotlin声明是var(读写属性)还是val(只读属性)进行具体提供
//定义Person类,私有属性,会提供公有的set和get方法 class Person { var name: String? = null get() = field set(value) { field = value } var age: Int? = 18 } fun main(args: Array<String>) { val person: Person = Person() person.name = "demo" println("创建的person对象,name赋值为:${person.name}") person.age = 20 println("创建的person对象,age赋值为:${person.age}") }
-
类的计算属性和防范空的情况
class Person2 { var name: String? = null //计算属性,针对于只读属性val进行操作 val randomNum: Int get() = (1..100).shuffled().first() //属性防范空的情况 public fun getNameInfo(): String { return name?.let { "成功赋值,值的内容是:${name}" } ?: "没有赋值,当前为null" } } fun main(args: Array<String>) { var person: Person2 = Person2() //计算属性的获取 println(person.randomNum) //默认为空的输出情况 println(person.getNameInfo()) //重新赋值情况 person.name = "zhangsan" println(person.getNameInfo()) }
-
类的主构造
作用: 主要是为了在声明时进行初始化
注意: 主构造的变量默认为临时类型,在声明创建后不能获取该临时变量.若需要使用,则需要声明主构造中的变量属性或者赋值在类内部声明变量
- 默认构造并且赋值到类的内部变量进行访问
//默认主构造且采取赋值到类内部变量 class Person(_name: String, _age: Int) { var name: String = _name var age: Int = _age } fun main(args: Array<String>) { var person: Person = Person("zhangsan", 20) // person._name -> 无法进行该访问 println("Person初始化内容信息为:name = ${person.name}; age = ${person.age}") }
- 声明主构造变量的变量属性, val 或者 var
class Person(var name: String, var age: Int) { } fun main(args: Array<String>) { var person: Person = Person("zhangsan", 20) println("Person初始化内容信息为:name = ${person.name}; age = ${person.age}") }
-
次构造函数
作用: 可初始化类中的部分属性
注意: 可重载;需实现主构造,为主构造赋值,让主构造统一管理
class Person(_name: String) { var Cname: String = _name var Cage: Int = 18 var Cinfo: String? = null constructor(name: String, age: Int) : this(name) { println("次构造函数中的属性为:name=${name};age=${age}") this.Cname = name this.Cage = age } constructor(name: String, age: Int, info: String?) : this(name) { println("次构造函数中的属性为:name=${name};age=${age};info=${info}") this.Cname = name this.Cage = age this.Cinfo = info } } fun main(args: Array<String>) { var person1: Person = Person("zhangsan") println(person1.Cname) var person2: Person = Person("zhangsan", 20) println("Person初始化内容信息为:name = ${person2.Cname}; age = ${person2.Cage}") var person3: Person = Person("zhangsan", 20, "个人信息") println("Person初始化内容信息为:name = ${person3.Cname}; age = ${person3.Cage}; info = ${person3.Cinfo}") }
-
类参数的默认值和调用顺序
优先调用主构造函数,其次再为次构造函数
主构造是在init代码块中,次构造是在contructor中进行
3.2 init代码块
-
相当于java中的代码块{} ,但不是静态代码块{}
class Person(name: String, password: String) { init { println("主构造函数调用") require(name.isNotBlank()) { "参数为空" } } constructor(name: String, password: String, info: String) : this(name, password) { println("次构造函数参数为:name=${name};password:${password};info=${info}") } } fun main(args: Array<String>) { var person: Person = Person("zhangsan", "123456", "个人") }
3.3 懒加载: lateinit
-
用法: 在属性上进行的操作,通过关键字lateinit实现变量的懒加载.通过 ::变量名.isInitialized 获取变量名是否已经初始化
fun main() { var b: Base = Base() b.initInfo() //需要先加载属性,才能进行使用 b.showInfo() } class Base { //延迟初始化,用到的时候在进行加载数据 lateinit var info: String fun initInfo() { info = "成功" } fun showInfo() { if (::info.isInitialized) { println(info) } else { println("忘记加载内容") } } }
3.4 惰性加载: by lazy
-
用法: 作用在变量名上,需要实现by lazy中的方法
fun main() { //var b: Base = Base() //Thread.sleep(5000) //println(b.database) var b: Base = Base() Thread.sleep(5000) println(b.database2) } class Base { //val database: String = readSqlDataBase() val database2 by lazy { readSqlDataBase() } fun readSqlDataBase(): String { println(1) println(2) println(2) println(2) println(2) println(2) println(2) println(2) println(1) return "Mysql" } }
3.5 类的继承与重写
-
继承: 通过 : 完成父到子的继承
-
重写: 方法名相同,存在于继承之间
fun main() { var b: Base = Child("zhangsan") b.basePrintln() } // kotlin所有的类和函数都是final属性的,如果需要可继承,则需要加入open关键字 open class Base(private val name: String) { private fun showName(): String { return "父类:姓名是:${name}" } open fun basePrintln() = println(showName()) } class Child(private val subname: String) : Base(subname) { private fun showName(): String { return "子类:姓名是:${subname}" } override fun basePrintln() = println(showName()) }
3.6 类的类型转化
-
存在父类和子类之间的转化,调用父类或者子类的方法
import java.io.File fun main() { var b: Base = Child("zhangsan") b.basePrintln() println(b is Base) println(b is Child) println(b is File) //is+as进行转换 if (b is Child) { (b as Child).basePrintln() } if (b is Base) { println((b as Base).test()) } } // kotlin所有的类和函数都是final属性的,如果需要可继承,则需要加入open关键字 open class Base(private val name: String) { private fun showName(): String { return "父类:姓名是:${name}" } open fun basePrintln() = println(showName()) fun test(): String { return "父类:姓名是:${name}" } } class Child(private val subname: String) : Base(subname) { private fun showName(): String { return "子类:姓名是:${subname}" } override fun basePrintln() = println(showName()) }
-
在调用的过程中,如果之前有进行as转化,那之后在使用时,就是as转化后的对象
import java.io.File fun main() { var b: Base = Child("zhangsan") b.basePrintln() //智能声明类型,已确定后续使用子类的方法 (b as Child).childPrintln() b.childPrintln() } // kotlin所有的类和函数都是final属性的,如果需要可继承,则需要加入open关键字 open class Base(private val name: String) { private fun showName(): String { return "父类:姓名是:${name}" } open fun basePrintln() = println(showName()) } class Child(private val subname: String) : Base(subname) { private fun showName(): String { return "子类:姓名是:${subname}" } fun childPrintln() = println(showName()) }
3.7 Any超类
-
任何类的父类,提供了规范接口定义
fun main() { //Any类的toString只提供标准,不提供实现 println(obj().toString()) } //每个类都默认继承了Any类 class obj : Any() { }
3.8 类的单例对象: object
-
作用: 在类上的声明,使得类成为为单例模式
fun main() { println(Base) println(Base) println(Base) println(Base) println(Base) println(Base.show()) } //单例的实例,也是类名,只有一个被创建 object Base { init { print("Base create") } fun show(): Unit { println("show函数") } }
3.9 对象表达式
-
在继承接口时,只能使用唯一的一种方式进行创建对象 object:类型{实现方法}
fun main() { var it: Base = object : Base() { override fun add(info: String) { //super.add(info) println("匿名对象add:${info}") } override fun del(info: String) { //super.del(info) println("匿名对象del:${info}") } } it.add("1234") it.del("12345") // 具名方式 var it2: Child = Child() it2.add("1234") it2.del("12345") // java的Runable实现 var p3: Runnable = object : Runnable { override fun run() { //TODO("Not yet implemented") println("Runable...") } } p3.run() var p4 = Runnable { println("run..") } p4.run() //KT接口只有一种对象表达式,没有简洁的写法,对象表达式object:类型{实现方法} object : RunableKT { override fun run() { //TODO("Not yet implemented") println("1111run") } }.run() } open class Base { open fun add(info: String) = println("add: ${info}") open fun del(info: String) = println("del: ${info}") } class Child : Base() { override fun add(info: String) { //super.add(info) println("具名对象add:${info}") } override fun del(info: String) { //super.del(info) println("具名对象add:${info}") } } interface RunableKT { fun run() }
3.10 伴生对象: companion
-
只会创建一次,类似于Java中的static静态块
fun main() { println(Base.info) Base.showInfo() } //因为kotlin中没有java的那种static静态,所以产生了compannon伴生对象 //无论创建多少次companion只创建一次 class Base { companion object { const val info: String = "demo" fun showInfo(): Unit = println("info: $info") } }
3.11 内部类和嵌套类
-
默认情况下是嵌套类,类的内部的类含有inner关键字才能内部类
-
内部类可以访问外部的属性,嵌套类不能访问外部属性
fun main() { Body("isOk").Heart().run() Body("isOk").Hand().Left().run() Outer.Net().showInfo("info") } //外部和内部类 class Body(_bodyInfo: String) { val bodyInfo: String = _bodyInfo fun show() { Heart().run() } // inner 使得内部类可以访问外部类,外部类可以直接访问内部的类 inner class Heart { fun run(): Unit = println("心跳运行:${bodyInfo}") } inner class Hand { inner class Left { fun run(): Unit = println("左手:${bodyInfo}") } } } //默认情况下就是嵌套类,除非是由外部类传递到内部类 class Outer { val info: String = "ok" fun show() { Net().showInfo(info) } class Net { fun showInfo(info: String): Unit = println(info) } }
3.12 普通类和数据类
-
普通类: 具有get和set、构造函数
-
数据类: 除了普通类具有的get、set和构造函数外,还提供了解构、克隆、toString、HashCode、equals方法
fun main() { println(ResponseBean(200, "ok", "成功")) println(ResponsedataBean(200, "ok", "成功")) //默认继承的Any父类equals时,是一种对象比较 println(ResponseBean(200, "ok", "成功") == ResponseBean(200, "ok", "成功")) //数据类重写了equals,所以是在对值的比较 println(ResponsedataBean(200, "ok", "成功") == ResponsedataBean(200, "ok", "成功")) } //普通类:具有set和get、构造函数 class ResponseBean(var code: Int, var msg: String, var data: Any) { } //数据类:除了set和get、构造函数外,还提供解构、克隆、toString、HashCode、equals方法 //服务器相应,javaBean,实体可以使用,主要就是数据存储载入,便于打印 //至少又一个参数的构造参数,且必须指明参数的类型 val 或 var //数据类不能使用 abstract,open,sealed,inner //比较,copy,toString,解构等 data class ResponsedataBean(var code: Int, var msg: String, var data: Any) { }
3.13 类的复制函数: Copy
-
类的复制函数,只复制了类的主构造方法,不管类的次构造方法
fun main() { var bo: BaseObject = BaseObject("zhangsan") println(bo) // copy、toString、hashCode只看主构造的参数信息,不管次构造的参数信息 var copybo: BaseObject = bo.copy(name = "wangwu") println(copybo) } data class BaseObject(var name: String, var age: Int) { var coreMsg: String = "" init { println("主构造被调用") } constructor(name: String) : this(name, 99) { println("此构造被调用") coreMsg = "核心信息" } override fun toString(): String { //return super.toString() return "toString: name: ${name};age: ${age};coreMsg: $coreMsg" } }
3.14 数据类的解构
-
在普通类中也可以实现解构造,需要运算符重载
fun main() { val (name, age, sex) = CommClass("zhangsan", 14, '男') println("普通类:name: ${name};age:${age};sex:${sex}.") val (name2, age2, sex2) = CommDataClass("zhangsan", 14, '男') println("数据类:name: ${name2};age:${age2};sex:${sex2}.") val (name3, _, sex3) = CommDataClass("zhangsan", 14, '男') println("数据类:name: ${name3};sex:${sex3}.") } class CommClass(var name: String, var age: Int, var sex: Char) { //解构需要运算符重载关键字 operator operator fun component1() = name operator fun component2() = age operator fun component3() = sex } data class CommDataClass(var name: String, var age: Int, var sex: Char) { }
3.15 运算符重载: operator
-
通过重写对应的方法,以实现对应所需要的功能
fun main() { println(Add(1, 2) + Add(2, 3)) } class Add(var num1: Int, var num2: Int) { operator fun plus(add: Add): Int { return num1 + add.num1 + num2 + add.num2 } //operator fun Add. 查看整个运算符重载的方式 }
3.16 枚举类: enum
-
简单声明使用
fun main() { println(Week.星期一) println(Week.星期六) //枚举的值等于枚举本身 println(Week.星期三 is Week) } // 枚举也是一个class enum class Week { 星期一, 星期二, 星期三, 星期四, 星期五, 星期六, 星期日 }
-
枚举类定义函数
fun main() { //调用显示 println(BodyPart.LEFT_HAND.show()) println(BodyPart.RIGHT_HAND.show()) println(BodyPart.LEFT_FOOT.show()) println(BodyPart.RIGHT_FOOT.show()) //更新数据 BodyPart.LEFT_HAND.update(BodyInfo("left_hand", 32)) } //枚举的主构造参数必须和枚举的参数保持一致 enum class BodyPart(private val bodyInfo: BodyInfo) { LEFT_HAND(BodyInfo("LEFT_HAND", 12)), RIGHT_HAND(BodyInfo("RIGHT_HAND", 12)), LEFT_FOOT(BodyInfo("LEFT_FOOT", 12)), RIGHT_FOOT(BodyInfo("RIGHT_FOOT", 12)), //结束枚举的值 ; fun show(): String = "四肢的信息是:${bodyInfo.flag},长度为:${bodyInfo.length}" fun update(newBodyInfo: BodyInfo): Unit { println("更新前Emnu数据,${this.bodyInfo.show()}") this.bodyInfo.flag = newBodyInfo.flag this.bodyInfo.length = newBodyInfo.length println("重新定义Emnu数据成功,${this.bodyInfo.show()}") } } class BodyInfo(var flag: String, var length: Int) { fun show(): String { return "${flag}的长度为:${length}" } }
-
代数数据类型
fun main() { println(Teacher(Exam.GRAD4).show()) } enum class Exam { GRAD1, GRAD2, GRAD3, GRAD4, ; } class Teacher(private val exam: Exam) { fun show(): String = //枚举属于代数数据类型,所以不需要else when (exam) { Exam.GRAD1 -> "分数低" Exam.GRAD2 -> "分数中下" Exam.GRAD3 -> "分数中上" Exam.GRAD4 -> "分数高" } }
3.17 密封类: sealed
-
枚举类的一种特殊情况
fun main() { println(Teacher(Exam.GRAD4("zhangsan")).show()) //声明object是单例模式 println(Exam.GRAD1 == Exam.GRAD1) //class不是单例模式的 println(Exam.GRAD4("aaa") == Exam.GRAD4("aaa")) } sealed class Exam { object GRAD1 : Exam() object GRAD2 : Exam() object GRAD3 : Exam() //object GRAD4 : Exam() //var name: String? = null class GRAD4(val name: String) : Exam() } class Teacher(private val exam: Exam) { fun show(): String = //枚举属于代数数据类型,所以不需要else when (exam) { is Exam.GRAD1 -> "分数低" is Exam.GRAD2 -> "分数中下" is Exam.GRAD3 -> "分数中上" is Exam.GRAD4 -> "分数高,该学生的姓名是:${(this.exam as Exam.GRAD4).name}" } }
3.18 接口: interface
-
接口本身不能含有主构造;继承的接口不仅需要重写接口函数,也需要重写接口的成员;实现接口的部分全部要加入override关键字
fun main() { val usb1: IUSB = Mouse() println(usb1.insertUSB()) val usb2: IUSB = KeyBoard() println(usb2.insertUSB()) } //接口本身都是public open,接口不能含有主构造 //接口不仅仅要重写接口的函数,也要重写接口的成员 //接口实现的部分全部要加入override关键字 interface IUSB { var usbVersion: String var usbInsertDriver: String fun insertUSB(): String } class Mouse(override var usbVersion: String = "3.2", override var usbInsertDriver: String = "鼠标") : IUSB { override fun insertUSB(): String { //TODO("Not yet implemented") return "设备为:${usbInsertDriver},设备版本为:${usbVersion}" } } class KeyBoard : IUSB { override var usbVersion: String = "3.2" get() = field//TODO("Not yet implemented") set(value) { field = value ?: "该字段为空" } override var usbInsertDriver: String = "键盘" get() = field//TODO("Not yet implemented") set(value) { field = value ?: "该字段为空" } override fun insertUSB(): String { //TODO("Not yet implemented") return "设备为:${usbInsertDriver},设备版本为:${usbVersion}" } }
-
接口默认实现
fun main() { val usb1: USB2 = Mouse2() println(usb1.insertUSB()) val usb2: USB2 = KeyBoard2() println(usb2.insertUSB()) val usb3: USB2 = Mouse3() println(usb3.insertUSB()) } //接口不能给成员赋值 //任何类 接口等等 val代表只读,是没有在其后动态赋值 interface USB2 { val usbVersion: String get() = (1..100).shuffled().last().toString() val usbInsertDriver: String get() = "usb设备接入" fun insertUSB(): String } class Mouse3() : USB2 { override val usbVersion: String get() = super.usbVersion override val usbInsertDriver: String get() = super.usbInsertDriver override fun insertUSB(): String { //TODO("Not yet implemented") return "设备为:${usbInsertDriver},设备版本为:${usbVersion}" } } class Mouse2(override var usbVersion: String = "3.2", override var usbInsertDriver: String = "鼠标") : USB2 { override fun insertUSB(): String { //TODO("Not yet implemented") return "设备为:${usbInsertDriver},设备版本为:${usbVersion}" } } class KeyBoard2 : USB2 { override var usbVersion: String = "3.2" get() = field//TODO("Not yet implemented") set(value) { field = value ?: "该字段为空" } override var usbInsertDriver: String = "键盘" get() = field//TODO("Not yet implemented") set(value) { field = value ?: "该字段为空" } override fun insertUSB(): String { //TODO("Not yet implemented") return "设备为:${usbInsertDriver},设备版本为:${usbVersion}" } }
3.19 抽象类: abstract
-
可以有一些抽象方法,也可以有一些具体实现
fun main() { MainActivity().show() } abstract class BaseActivity { fun onCreate() { setContentView(getLayoutID()) initView() initData() initOthers() } private fun setContentView(laoutID: Int) = println("加载${laoutID}") abstract fun getLayoutID(): Int abstract fun initView() abstract fun initData() abstract fun initOthers() } class MainActivity : BaseActivity() { override fun getLayoutID(): Int { //TODO("Not yet implemented") return 562 } override fun initView() { //TODO("Not yet implemented") println("View 初始化") } override fun initData() { //TODO("Not yet implemented") println("data 初始化") } override fun initOthers() { //TODO("Not yet implemented") println("Ohters 初始化") } fun show() { super.onCreate() } }
3.20 泛型
-
普通泛型
fun main() { var s: Student = Student(name = "zhangsan", age = 19, sex = '男') BaseF(s).show() var t: Teacher = Teacher(name = "wangwu", age = 29, sex = '男') BaseF(t).show() BaseF(String(("留意").toByteArray())) } class BaseF<T>(private val obj: T) { fun show() = println("输出对象:${obj}") } data class Student(val name: String, val age: Int, val sex: Char) data class Teacher(val name: String, val age: Int, val sex: Char)
-
泛型函数
fun main() { var s: Student = Student(name = "zhangsan", age = 19, sex = '男') println(BaseF(true, s).getObj()) var t: Teacher = Teacher(name = "wangwu", age = 29, sex = '男') println(BaseF(true, t).getObj()) println(BaseF(false, t).getObj() ?: "返回了null呀") BaseF(true, s).getObj()?.run { println("对象为:${this}") } ?: "返回了null呀" var temp: Student? = BaseF(true, s).getObj()?.apply { if (this != null) { println("对象为:${this}") } else { println("返回了null呀") } } show("String") show2(null) } class BaseF<T>(private val isShow: Boolean = false, private val obj: T) { fun getObj() = obj.takeIf { isShow } } data class Student(val name: String, val age: Int, val sex: Char) data class Teacher(val name: String, val age: Int, val sex: Char) fun <B> show(item: B) { var result = item?.also { println("打印:${item}") } ?: println("返回了null呀") } fun <T> show2(item: T) { var r = item?.also { if (item == null) { println("null") } else { println("打印:${item}") } } ?: "返回了null呀" }
-
泛型变换
fun main() { var p1 = BaseF2(isMap = true, 321421) var r = p1.map { it.toString() } println(r is String?) println(r) var r1: String? = map(inputValue = 12345) { it.toString() } println(r1) } class BaseF2<T>(private val isMap: Boolean = false, val inputType: T) { fun <R> map(mapAction: (T) -> R): R? = mapAction(inputType).takeIf { isMap } } inline fun <I, O> map(isChange: Boolean = true, inputValue: I, mapAction: (I) -> O): O? { return if (isChange) mapAction(inputValue) else null }
-
泛型类型的约束
fun main() { val my = MyClass("1234") val person = PersonClass("1234") val student = StudentClass("1234") val teacher = TeacherClass("1234") val dog = DogClass("1234") val r1 = PrintF(inputTypeValue = student).getObj(); println(r1) } open class MyClass(name: String) open class PersonClass(name: String) : MyClass(name) class StudentClass(name: String) : PersonClass(name) class TeacherClass(name: String) : PersonClass(name) class DogClass(name: String) // <T : 类型>,类型的以及类型的子类可以使用 class PrintF<T : PersonClass>(private val isChange: Boolean = true, val inputTypeValue: T) { fun getObj() = inputTypeValue.takeIf { isChange } }
3.21 动态关键字: vararg
-
声明的该属性可接收多个值
fun main() { // 类型: Baseargs<{Comparable<*> & java.io.Serializable}> var p: Baseargs<Any?> = Baseargs(ischange = true, true, "1234", 213.4) println(p.showObject(0)) println(p.showObject(2).toString() is String) var r: String = p.mapObj(1) { it as String } println(r) } class Baseargs<T>(var ischange: Boolean, vararg objects: T) { //out 指我们的T只能被读取,不能进行修改 val objectArray: Array<out T> = objects fun showObject(): Array<out T> { return objectArray } fun showObject(index: Int): T { return objectArray[index] } fun <O> mapObj(index: Int, mapAction: (T?) -> O): O { return mapAction(objectArray[index].takeIf { ischange }) } }
3.22 自定义操作符: []
-
重写操作符: []
fun main() { inputObj("demo") inputObj(null) var i: BaseClss<String?> = BaseClss(isChange = true, "zhangsan", "lisi", "wangwu") println(i.get(0)) println(i.get(2)) } class BaseClss<INPUT>(val isChange: Boolean, vararg objects: INPUT) { //out标识objectArray只能进行读取,不能进行修改 val objectArray: Array<out INPUT> = objects fun getObj(): Array<out INPUT> = objectArray fun getObj2(): Any = objectArray.takeIf { isChange } ?: "null值" fun getObj3(): Any? = objectArray.takeIf { isChange } ?: "null值" ?: null fun getObj4(index: Int): INPUT? = objectArray[index].takeIf { isChange } ?: null fun getObj5(index: Int): Any? = objectArray[index].takeIf { isChange } ?: "AAA" ?: null operator fun get(index: Int): INPUT? = objectArray[index].takeIf { isChange } } fun <INPUT> inputObj(item: INPUT) { println((item as String?)?.length ?: "传递的是null") }
3.23 out协变
-
父 -> 子
fun main() { var p1: Producer<Animal> = Produce1() //类型也可以为Animal,因为有out关键字,泛型的子类对象也可以赋值给父类对象,默认情况下不可以 //相当于java中的 ? extends 例如:List<? extends CharSequence> list2=new ArrayList<String>(); var p2: Producer<Animal> = Produce2() var p3: Producer<Animal> = Produce3() var p4: Producer<Animal> = Produce4() } //out T 协变 interface Producer<out T> { // 这里的T只能读取,不能修改,放在参数里,可能会产生修改 //fun consumer(item:T){} fun Produce(): T } //in T 逆变 interface Consumer<in T> { fun Consume(item: T) //不能进行读取,只能修改 //fun Produce():T } interface ProducerAndConsumer<T> { fun Produce(): T fun Consume(item: T) } open class Animal open class Humanity : Animal() open class Man : Humanity() open class Woman : Humanity() class Produce1 : Producer<Animal> { override fun Produce(): Animal { //TODO("Not yet implemented" println("Animal Produce") return Animal() } } class Produce2 : Producer<Humanity> { override fun Produce(): Humanity { //TODO("Not yet implemented" println("Humanity Produce") return Humanity() } } class Produce3 : Producer<Man> { override fun Produce(): Man { //TODO("Not yet implemented" println("Man Produce") return Man() } } class Produce4 : Producer<Woman> { override fun Produce(): Woman { //TODO("Not yet implemented" println("Woman Produce") return Woman() } }
3.24 in 逆变
-
子 -> 父
// out 协变:只读 父类 = 子类 // in 逆变:只写 子类 = 父类 fun main() { var p1: Producer<Animal> = Produce1() //类型也可以为Animal,因为有out关键字,泛型的子类对象也可以赋值给父类对象,默认情况下不可以 //相当于java中的 ? extends 例如:List<? extends CharSequence> list2=new ArrayList<String>(); var p2: Producer<Animal> = Produce2() var p3: Producer<Animal> = Produce3() var p4: Producer<Animal> = Produce4() //因为有in关键字,泛型的子类对象也可以接收父类的对象,默认情况下是不可以 //相当于java中的 ? super 例如:List<? extends String> list2=new ArrayList<CharSequence>(); val c1: Consumer<Man> = Consume1() } //out T 协变 interface Producer<out T> { // 这里的T只能读取,不能修改,放在参数里,可能会产生修改 //fun consumer(item:T){} fun Produce(): T } //in T 逆变 interface Consumer<in T> { fun Consume(item: T) //不能进行读取,只能修改 //fun Produce():T } interface ProducerAndConsumer<T> { fun Produce(): T fun Consume(item: T) } open class Animal open class Humanity : Animal() open class Man : Humanity() open class Woman : Humanity() class Produce1 : Producer<Animal> { override fun Produce(): Animal { //TODO("Not yet implemented" println("Animal Produce") return Animal() } } class Produce2 : Producer<Humanity> { override fun Produce(): Humanity { //TODO("Not yet implemented" println("Humanity Produce") return Humanity() } } class Produce3 : Producer<Man> { override fun Produce(): Man { //TODO("Not yet implemented" println("Man Produce") return Man() } } class Produce4 : Producer<Woman> { override fun Produce(): Woman { //TODO("Not yet implemented" println("Woman Produce") return Woman() } } class Consume1 : Consumer<Animal> { override fun Consume(item: Animal) { //TODO("Not yet implemented") println("Animal Consume") } } class Consume2 : Consumer<Humanity> { override fun Consume(item: Humanity) { //TODO("Not yet implemented") println("Humanity Consume") } } class Consume3 : Consumer<Man> { override fun Consume(item: Man) { //TODO("Not yet implemented") println("Man Consume") } } class Consume4 : Consumer<Woman> { override fun Consume(item: Woman) { //TODO("Not yet implemented") println("Woman Consume") } }
3.25 out和in的用法
fun main() {
val p1: SetClass<String> = SetClass<String>();
p1.set1("1234213")
val o1: GetClass<String> = GetClass<String>("param");
println(o1.get1())
}
// in T 或者 out T 声明处泛型 ,java不支持
//所有的成员 泛型相关只能修改更改,不能读取
class SetClass<in T>() {
fun set1(item: T) {
println("设置的item为:${item}")
}
}
//所有的成员 泛型相关只能读取,不能更改
class GetClass<out T>(_item: T) {
val item: T = _item
fun get1(): T? {
return item
}
}
3.26 reified关键字
fun main() {
//匿名方式
var r = AllFun().randomOrDefault<ObjectClass1> {
ObjectClass1("wangwu", 20)
}
println(r)
//具名方式
var r1: ObjectClass1? = AllFun().randomOrDefault<ObjectClass1>(::defaultAction)
println(r1)
}
data class ObjectClass1(val name: String, val age: Int)
data class ObjectClass2(val name: String, val age: Int)
data class ObjectClass3(val name: String, val age: Int)
fun <T> defaultAction(): T {
return ObjectClass1("wangwu", 20) as T
}
class AllFun {
inline fun <reified T> randomOrDefault(defaultLambdaAction: () -> T): T? {
var objLists: List<Any> = listOf<Any>(
ObjectClass1("wangwu", 12),
ObjectClass2("zangsan", 12),
ObjectClass3("lsii", 12)
)
val randomObj: Any? = objLists.shuffled().first()
println("随机产生的对象为:${randomObj}")
//return randomObj.takeIf { it is T } as T ?: null
return randomObj.takeIf { it is T } as T? ?: defaultLambdaAction()
}
}
3.27 扩展函数
-
基本扩展
fun main() { val baseClass: BaseClass = BaseClass("zhangsan", 18, '男') baseClass.show() println("Demo".addExtAction(3)) } class BaseClass(val name: String, val age: Int, val sex: Char) //每个扩展类函数中都含有一个this,this代表类的本身 fun BaseClass.show() { println("name:${this.name},age:${age},sex:${sex}") } fun BaseClass.getAge(): Int = this.age fun String.addExtAction(num: Int) = this + "@".repeat(num)
-
超类扩展
fun main() { ResponseResult(200, "ok", "成功").showPrintlnContent() "提示信息".showPrintlnContent() "提示信息".showPrintlnContent2().showPrintlnContent2() } //扩展函数不允许重复定义 fun Any.showPrintlnContent() = println("当前的对象是:${this}") //链式调用 fun Any.showPrintlnContent2(): Any { println("当前的对象为:${this}") return this } data class ResponseResult(val code: Int, val status: String, val msg: String)
-
泛型扩展
fun main() { //所有的类型都是泛型,所以所有的类均可以调用showContentInfo函数 123.showContentInfo() "1234".showContentInfo() contentFun().showContentInfo() } fun <T> T.showContentInfo() { println("${if (this is String) "字符长度为:${this.length}" else "内容为:${this}"} ") } fun contentFun() { }
-
apply内置函数扩展
fun main() { "Demo".myLet { true } "demo".let { true } } private inline fun <I, O> I.myLet(lambda: (I) -> O): O = lambda(this)
-
扩展属性
fun main() { var str: String = "abc" str.getInfo().getInfo() str.myinfo.getInfo() } val String.myinfo: String get() = "demo" fun String.getInfo(): String { println("当前内容是:${this}") return this }
-
可用类型的应用
fun main() { var info: String? = null info.outPutStringValueFun("默认值") } //String?可以接收可空数据,也可以接收有值数据 fun String?.outPutStringValueFun(defaultValue: String): Unit { println(this ?: defaultValue) } fun String?.outPutStringValueFun2(defaultValue: String): String { return this ?: defaultValue }
3.28 中缀表达式
fun main() {
mapOf("0".to(12))
mapOf("1".to(23120))
"demo".goto(1234)
"demo" goto 12341
}
//中缀表达式 + 扩展函数
//条件:对一个对象需要进行函数扩展,另一个对象需要传递在参数内
private infix fun <C1, C2> C1.goto(c2: C2) {
println("参数1:${this}")
println("参数2:${c2}")
}
3.29 扩展文件
fun main() {
val list: List<String> = listOf("12", "23124", "312412")
val set: Set<Int> = setOf(1, 2, 3, 5, 9)
println(list.shuffled().first())
println(set.shuffled().first())
println(list.randomItemValue())
set.randomItemValuePrintln()
}
//扩展文件一般都是public,重写父类主要是为了子类可以使用
fun <E> Iterable<E>.randomItemValue(): E {
return this.shuffled().first()
}
fun <T> Iterable<T>.randomItemValuePrintln() = println(this.shuffled().first())
3.30 重命名 as
主要用法:import 方法名 as 别名
3.31 apply解析扩展
-
一般扩展
fun main() { "str".mApply { println(this.length) }.mApply { println(this is String) } } //private 私有化 //inline 函数属于高阶函数,使用内联对lambda进行优化处理提高新能 //fun<INPUT> 函数中声明一个泛型 //INPUT.mApply 让所有类型都可以进行调用,泛型扩展 // INPUT.()->Unit 让我们的匿名函数中持有this,在lambda里面返回类型为空 // 调用lambda(this) 默认就含有this //返回this的目的主要是用链式调用 private inline fun <INPUT> INPUT.mApply(lambda: INPUT.() -> Unit): INPUT { lambda() return this }
-
let和apply总结
//1. let 返回类型是根据匿名函数的变化而变化(lambda的返回类型变化而变化) //2。 匿名函数李曼持有的是 it对象 inline fun <I, O> I.mLet(lambda: (I) -> O): O = lambda(this) //1. apply返回类型永远都是I,lambda的返回类型与apply返回类型并无关联 //2. 匿名函数里面持有的是 this对象 inline fun <I> I.mApply(lambda: I.() -> Unit): I { lambda() return this }
3.32 DSL
//DSL(Domain Specified Language),领域专用语言
//定义输入和输出规则;
//定义使用的对象
fun main() {
val context: Context = Context().apply1 {
toast("success")
toast(it)
}
println(context)
}
class Context {
val info = "demo"
fun toast(str: String): Unit {
println("Toast: $str")
}
}
fun Context.apply1(lambda: Context.(String) -> Unit): Context {
lambda(this.info)
return this
}
3.33 函数变换
-
map的函数变换
fun main() { val list: List<String> = listOf("123", "1234", "12", "1") //通过匿名函数的最后一行返回值加入新的集合,并返回新的集合 val list1: List<String> = list.map { println(it) "{$it}" } println(list1) list.map { "字符串是:$it" }.map { "$it,文字的长度是:${it.length}" }.map { "[$it]" }.map { println(it) } }
-
flatmap的函数变换
fun main() { val list: List<String> = listOf("zhangsan", "lisi", "wangwu") //map 返回每一个元素的加入到新的集合 List<String> //flatmap 返回每一个集合加入到新的集合 List<List<String>> val newlist: List<String> = list.map { "你的姓名是:$it" }.map { "$it,文字的长度是:${it.length}" }.flatMap { listOf("$it 在1", "$it 在2") } println(newlist) val list2: List<String> = list.flatMap { listOf("$it 在1", "$it 在2") } println(list2) }
3.34 filter函数过滤
fun main() {
val names: List<List<String>> = listOf(
listOf("zhangsan", "wangwu", "zhaoliu"),
listOf("lisi", "wanger", "wuli")
)
names.map {
println(it)
}
names.flatMap {
println(it)
listOf("")
}
//返回的对象为String
names.flatMap { it ->
//filter:如果为true 加入到新的集合中进行组装;否则不加入
it.filter {
println("$it,1")
false
}
}.map {
println(it)
}
// 返回的类型为List<String>
names.map { it ->
//filter:如果为true 加入到新的集合中进行组装;否则不加入
it.filter {
//println("$it,1")
true
}
}.map {
println(it)
}
names.flatMap { it ->
it.filter {
it.contains("zhao")
}
}.map {
print("$it ")
}
}
3.35 zip合并函数
fun main() {
val names: List<String> = listOf("zhangsan", "lisi", "wangwu")
val ages: List<Int> = listOf(19, 29, 31)
//zip 第一个集合和第二个集合进行合并后,创建新的集合
var new: List<Pair<String, Int>> = names.zip(ages)
println(new)
println(new.toMap())
println(new.toMutableSet())
println(new.toMutableList())
//遍历
new.forEach() {
println("第一个:${it.first},第二个:${it.second}")
}
//map普通方式
new.toMap().forEach() { key: String, value: Int ->
println("第一个:${key},第二个:${value}")
}
//map的解构方式
new.toMap().forEach() { (key: String, value: Int) ->
println("第一个:${key},第二个:${value}")
}
}
3.36 函数式编程
3.37. java与kotlin交互
public class DemoCon {
public String getInfo() {
return "Demo";
}
public String getInfo2() {
return null;
}
}
fun main() {
//交互时不能直接使用,可能会出现异常错误提示
//println(DemoCon().info.length)
//println(DemoCon().info2.length)
//java与kotlin交互式类型都是 :类型!
val info: String? = DemoCon().info
val info1: String? = DemoCon().info2
println(info?.length)
println(info1?.length)
}
3.38 单例模式的四种方式
// kotlin的饿汉模式加载
object Singleton
//kotlin的懒汉式加载
class Singleton2 {
companion object {
private var instance: Singleton2? = null
get() {
if (field == null) {
field = Singleton2()
}
return field
}
//fun getInstanceAction(): Singleton2 = instance!!
//懒汉式处理+安全处理
@Synchronized
fun getInstanceAction(): Singleton2 = instance!!
}
fun show() {
println("show")
}
}
//懒汉式处理+双重安全处理
class Singleton3 {
companion object {
val instance: Singleton3 by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
Singleton3()
}
}
fun show() {
println("show")
}
}
fun main() {
//Singleton2.getInstanceAction().show()
Singleton3.instance.show()
}
3.39 kotlin 注解
-
JvmName
public class JvmNameJava { public static void main(String[] args) { //JvmNameAndkotlinKt.getJvmNameJavaInfo("1234"); JNAK.getJvmNameJavaInfo("1234"); } }
//编译环节修改类名称,使得其他进行调用时更简洁,必须要写在包名外 @file:JvmName("JNAK") fun main() { } fun getJvmNameJavaInfo(str: String) = println(str)
-
JvmField
public class JvmFieldAndKotlin { public static void main(String[] args) { Text test = new Text(); // for (String item : test.getName()) { // System.out.println(item); // } for (String item : test.name) { System.out.println(item); } } }
class Text { //将成员的私有化方法去掉,属性变为公开可访问的 @JvmField val name: List<String> = listOf("zhangsan", "lisi") }
-
JvmOverloads
public class JvmOverloadsJava { public static void main(String[] args) { JvmOverloadsAndKotlinKt.show("1234"); } }
fun main() { show(name = "123") } //编译阶段会有一个重载函数供其调用 @JvmOverloads fun show(name: String, age: Int = 20) { println("name:${name},age:${age}") }
-
JvmStatic
public class JvmStaticJava { public static void main(String[] args) { //Test.Companion.getAddress(); //Test.Companion.show(); System.out.println(Test.address); Test.show(); } }
class Test { companion object { @JvmField val address = "北京" @JvmStatic fun show() = println("当前的地址为:${address}") } } fun main() { Test.address Test.show() }
3.40 自定义变换操作符
fun main() {
//create 匿名表达式 只关心用户的输入 输出源是最后一行内容
//map 输入源就是create输出源 输出源为最后一行内容
//observer 输入源就是map存储的输出源
create {
"demo"
}.map {
"你的值是:$this"
}.map {
"{{${this}}}"
}.observer {
println(this)
}
}
class RxJavaCoreObjectClass<T>(val value: T) {
}
inline fun <I, O> RxJavaCoreObjectClass<I>.map(mapAction: I.() -> O): RxJavaCoreObjectClass<O> {
return RxJavaCoreObjectClass(mapAction(value))
}
inline fun <OUTPUT> create(action: () -> OUTPUT): RxJavaCoreObjectClass<OUTPUT> {
return RxJavaCoreObjectClass<OUTPUT>((action()))
}
inline fun <INPUT> RxJavaCoreObjectClass<INPUT>.observer(observerAction: INPUT.() -> Unit): Unit {
observerAction(value)
}
评论区