文章目录

  • 1.空检查
  • 2.数据类型
  • 3.in表达式
  • 4.when表达式
  • 5.字符串模板
  • 6.函数头
  • 7.默认参数
  • 8.具名参数
  • 9.Unit类型
  • 10.Nothing类型特点
  • 11.反引号函数名
  • 12.函数
    • 1.匿名函数
    • 2.函数类型&隐式返回
    • 2.函数参数
    • 3.it关键字
    • 4.匿名函数的类型推断
    • 5.lambda学习
    • 6.入参为函数
    • 6.返回类型为函数
    • 7.匿名函数跟具名函数
  • 13.操作符
    • 1.let
    • 2. ?: 空合并操作符
    • 3.自定义异常
    • 4.先决条件函数
    • 5.substring
    • 6.split
    • 7.replace
    • 8. ==跟 ===的区别
    • 9.字符串遍历forEach
    • 10.toInt(),toIntOrNull()
    • 11.roundToInt()
    • 12.apply、
    • 13.also、apply、let、run、with、takeIf、takeUnless
    • 14.run
    • 15.with
    • 16.also
    • 17.takeIf
    • 17.takeUnless
  • 14.集合
    • 1.listOf(),getOrNull,getOrElse;setOf(),elementAtOrElse,elementAtOrNull
    • 2.mutableListOf跟listOf的相互转换
    • 3.+=,-=跟removeIf
    • 3.list遍历
    • 4.解构语法过滤元素
    • 5.list去重
    • 6.kotlin数组类型
    • 7.map
  • 15.类
    • 1.Bean类
    • 2.构造函数
    • 3.lateinit延迟初始化
    • 4.open
    • 5.is、as
    • 6.Any()
    • 7.object单例
    • 8.对象表达式
    • 9.伴生对象
    • 10.嵌套类、内部类
    • 11.普通类、数据类
    • 12.copy函数
    • 13.解构
    • 14.运算符重载
    • 15.枚举类
    • 16.密封类
  • 16.接口
    • 1.接口定义
    • 2.修改接口的默认实现
    • 3.抽象类
    • 4.泛型
  • 17.扩展函数
  • 18扩展属性
  • 19.扩展文件及扩展函数重命名
  • 19.infix中缀函数

1.空检查

?:表示为空则不执行后面
!!:表示一定执行后面

    // TODO 第一种情况:默认是不可空类型,所以不能给nullvar name: String = "Derry"// 提示:不能是非空类型String的值// name = nullprintln(name)// TODO 第二种情况:声明时指定为可空类型var name2: String ?name2 = null// name2 = "Derry"println(name2)

思考题:kotlin是静态语言还是动态语言?
静态语言,因为在编译期就决定了类型。

2.数据类型

String      字符串
Char        单字符
Boolean     true/false
nt         整形
Double      小数
List        集合
set         无重复的元素集合
map         键值对的集合int   ---> java int
float  ---> java float// Java语言有两种数据类型:
//      第一种:基本类型:int double 等
//      第二种:引用类型 String 等
// Kotlin语言只有一种数据类型:
//      看起来都是引用类型,实际上编译器会在Java字节码中,修改成 “基本类型”,所以不会耗费性能

3.in表达式

if (number in 10..59) {//含头含尾println("不及格")
}

4.when表达式

    // Java的 if 语句// KT的 if 是表达式 有返回值的val info = when(week) {1 -> "今天是星期一,非常忙碌的一天开会"2 -> "今天是星期二,非常辛苦的写需求"3 -> "今天是星期三,努力写Bug中"4 -> "今天是星期四,发布版本到凌晨"5 -> "今天是星期五,淡定喝茶,一个Bug改一天"6 -> "今天是星期六,稍微加加班"7 -> "今天是星期七,看剧中,游玩中"else -> {println("养猪去了,忽略星期几")}}println(info) //Kolint.Unit

5.字符串模板

     val garden = "黄石公园"val time = 6println("今天天气很晴朗,去玩" + garden + ",玩了" +time +" 小时") // Java的写法println("今天天气很晴朗,去${garden}玩,玩了$time 小时") // 字符串模版的写法// KT的if是表达式,所以可以更灵活,  Java的if是语句,还有局限性val isLogin = falseprintln("server response result: ${if (isLogin) "恭喜你,登录成功√" else "不恭喜,你登录失败了,请检查Request信息"}")

6.函数头

// 函数默认都是public
// 其实Kotlin的函数,更规范,先有输入,再有输出
private fun method01(age: Int, name: String) : Int {println("你的姓名是:$name,你的年龄是:$age")return 200
}/* 上面的Kt函数,背后会变成下面的Java代码:private static final int method01(int age, String name) {String var2 = "你的姓名是:" + name + ",你的年龄是:" + age;boolean var3 = false;System.out.println(var2);return 200;}*/

7.默认参数

// TODO 17.Kotlin中函数参数的默认参数
fun main() {action01("lisi", 89)action02("wangwu")action03()action03("赵六", 76)
}private fun action01(name: String, age: Int) {println("我的姓名是:$name, 我的年龄是:$age")
}private fun action02(name: String, age: Int = 77) {println("我的姓名是:$name, 我的年龄是:$age")
}private fun action03(name: String = "王五", age: Int = 67) {println("我的姓名是:$name, 我的年龄是:$age")
}

8.具名参数

// TODO 18.Kotlin语言的具名函数参数
fun main() {loginAction(age = 99, userpwd = "123", usernam = "de", username = "Derry", phonenumber = "123456")
}private fun loginAction(username: String, userpwd: String, phonenumber: String, age: Int, usernam: String) {println("username:$username, userpwd:$userpwd, phonenumber:$phonenumber, age:$age")
}

9.Unit类型

// Java语言的void关键字(void是 无参数返回的 忽略类型) 但是他是关键帧啊,不是类型,这很矛盾
// : Unit不写,默认也有,Unit代表  无参数返回的 忽略类型 == Unit类型类
private fun doWork() : Unit {return println()
}private fun doWork2() {return println()
}

10.Nothing类型特点

// TODO 20.Kotlin语言的Nothing类型特点
fun main() {show(-1)
}private fun show(number: Int) {when(number) {-1 -> TODO("没有这种分数")in 0..59 -> println("分数不及格")in 60..70 -> println("分数及格")in 71..100 -> println("分数优秀")}
}interface A {fun show()
}class AImpl : A {override fun show() {// 下面这句话,不是注释提示,会终止程序的TODO("not implemented") //To change body of created functions use File | Settings | File Templates.}}

11.反引号函数名

反引号可以用来修饰函数名// TODO 21.Kotlin语言的反引号中函数名特点
fun main() {// 第一种情况:`登录功能 2021年8月8日测试环境下 测试登录功能 需求编码人是Derry`("Derry", "123456")// 第二种情况:// in  is  在kt里面就是关键字,怎么办呢? 使用反引号KtBase21.`is`()KtBase21.`in`()// 第三种情况: 很少发生`65465655475`()
}private fun `登录功能 2021年8月8日测试环境下 测试登录功能 需求编码人是Derry`(name: String, pwd: String) {println("模拟:用户名是$name, 密码是:$pwd")
}private fun `65465655475`() {// 写了很复杂的功能,核心功能// ...
}// 公司加密私有的文档     65465655475  === 此函数的作用 xxxx
// 公司加密私有的文档     55576575757  === 此函数的作用 xxxx

12.函数

1.匿名函数

fun main() {val len = "Derry".count()println(len)//5val len2 = "Derry".count {// it 等价于 D e r r y 的字符 Charit == 'r'}println(len2)//2
}

2.函数类型&隐式返回

fun main() {// 第一步:函数输入输出的声明val methodAction : () -> String// 第二步:对上面函数的实现methodAction = {val inputValue = 999999"$inputValue Derry" // == 背后隐式 return "$inputValue Derry";// 匿名函数不要写return,最后一行就是返回值}// 第三步:调用此函数println(methodAction())
}/*
fun methodAction() : String {return "Derry"
}*/

2.函数参数

fun main() {// 第一步:函数输入输出的声明   第二步:对声明函数的实现val methodAction : (Int, Int, Int) -> String = { number1, number2, number3 ->val inputValue = 999999"$inputValue Derry 参数一:$number1, 参数二:$number2, 参数三:$number3"}// 第三步:调用此函数println(methodAction(1, 2, 3))
}/*
fun methodAction(number1: Int, number2: Int, number3: Int) : String {val inputValue = 999999return "$inputValue Derry 参数一:$number1, 参数二:$number2, 参数三:$number3"
}*/

3.it关键字

fun main() {val methodAction : (Int, Int, Int) -> String = { n1, n2, n3 ->val number = 24364println("$number Derry ,n1:$n1, n2:$n2, n3:$n3")"$number Derry ,n1:$n1, n2:$n2, n3:$n3"}// methodAction.invoke(1,2,3)methodAction(1,2,3)val methodAction2 : (String) -> String = { "$it Derry" }println(methodAction2("DDD"))//DDD Derryval methodAction3 : (Double) -> String = { "$it Derry2" }println(methodAction3(5454.5))// 5454.5 Derry2
}/*fun methodAction2(it : String) : String { return "$it Derry" }*/

4.匿名函数的类型推断

fun main() {// 匿名函数,类型推断为String// 方法名 : 必须指定 参数类型 和 返回类型// 方法名 = 类型推断返回类型val method1 = { v1:Double, v2:Float, v3:Int ->"v1:$v1, v2:$v2, v3:$v3"} // method1 函数: (Double, Float, Int) -> Stringprintln(method1(454.5, 354.3f, 99))val method2 = {3453.3f} // method2 函数: () -> Unitprintln(method2())val method3 = { number: Int ->number} // method3 函数: (Int) -> Intprintln(method3(9))
}

5.lambda学习

fun main() {// 匿名函数 == lambda表达式val addResultMethod = { number1 : Int, number2: Int ->"两数相加的结果是:${number1 + number2}"} // addResultMethod 函数: (Int, Int) -> Stringprintln(addResultMethod(1, 1))// 匿名函数 入参 Int,          返回 Any类型// lambda表达式的参数 Int,    lambda表达式的结果Any类型val weekResultMethod = { number: Int ->when(number) {1 -> "星期1"2 -> "星期2"3 -> "星期3"4 -> "星期4"5 -> "星期5"else -> -1}} // weekResultMethod 函数: (Int) -> Anyprintln(weekResultMethod(2))// 匿名函数 属于 lambda
}

6.入参为函数

普通写法

fun main() {// 第一种方式  匿名函数loginAPI("Derry", "123456") { msg: String, code: Int ->println("最终登录的情况如下: msg:$msg, code:$code")}// 第二种方式loginAPI2("Derry", "123456", { msg: String, code:Int ->println("最终登录的情况如下: msg:$msg, code:$code")})// 第三种方式loginAPI2("Derry", "123456", responseResult = { msg: String, code: Int ->println("最终登录的情况如下: msg:$msg, code:$code")})// 第四种方式// 具名函数//函数引用 lambda属于函数类型的对象,需要把methodResponseResult普通函数变成 函数类型的对象(函数引用)login("Derry2", "123456", ::methodResponseResult)
}fun methodResponseResult(msg: String, code: Int) {println("最终登录的成果是:msg:$msg, code:$code")
}const val USER_NAME_SAVE_DB = "Derry"
const val USER_PWD_SAVE_DB = "123456"// 如果函数参数有lambda,尽量使用 inline关键帧,这样可以减少 函数开辟、对象开辟的损耗
inline fun loginAPI(username: String, userpwd: String, responseResult: (String, Int) -> Unit) {if (username == null || userpwd == null) {TODO("用户名或密码为null") // 出现问题,终止程序}if (username.length > 3 && userpwd.length > 3) {if (wbeServiceLoginAPI(username, userpwd)) {responseResult("login success", 200)} else {responseResult("login error", 444)}} else {TODO("用户名和密码不合格") // 出现问题,终止程序}
}// 登录的API暴露者 服务器
private fun wbeServiceLoginAPI(name: String, pwd: String) : Boolean {// kt的if是表达式(很灵活)     java的if是语句(有局限性)return if (name == USER_NAME_SAVE_DB && pwd == USER_PWD_SAVE_DB) true else false
}

Java写法


interface ResponseResult {void result(String msg, int code);
}public class KTBase29 {public final static String USER_NAME_SAVE_DB = "Derry";public final static String USER_PWD_SAVE_DB = "123456";public static void main(String[] args) {loginAPI("Derry2", "123456", new ResponseResult() {@Overridepublic void result(String msg, int code) {System.out.println(String.format("最终登录的情况如下: msg:%s, code:%d", msg, code));}});}// 登录API 模仿 前端public static void loginAPI(String username, String userpwd, ResponseResult responseResult) {if (username == null || userpwd == null) {// TODO("用户名或密码为null") // 出现问题,终止程序}if (username.length() > 3 && userpwd.length() > 3) {if (wbeServiceLoginAPI(username, userpwd)) {responseResult.result("login success", 200);} else {responseResult.result("login error", 444);}} else {// TODO("用户名和密码不合格") // 出现问题,终止程序}}// 登录的API暴露者 服务器private static boolean wbeServiceLoginAPI(String name, String pwd) {// kt的if是表达式(很灵活)     java的if是语句(有局限性)if (name == USER_NAME_SAVE_DB && pwd == USER_PWD_SAVE_DB)return true;elsereturn false;}
}

6.返回类型为函数

fun main() {val r = show("学习KT语言")// r 是show函数的 返回值val niming_showMethod = showMethod("show")// niming_showMethod 是 showMethod函数的返回值 只不过这个返回值 是一个 函数// niming_showMethod == 匿名函数println(niming_showMethod("Derry", 33))
}fun show(info: String): Boolean {println("我是show函数 info:$info")return true
}fun show2(info: String): String {println("我是show函数 info:$info")return "DDD"
}// showMethod函数 再返回一个 匿名函数
fun showMethod(info: String): (String, Int) -> String {println("我是show函数 info:$info")// return 一个函数 匿名函数return { name: String, age: Int ->"我就是匿名函数:我的name:$name, age:$age"}
}

7.匿名函数跟具名函数

fun main() {// 匿名函数showPersonInfo("lisi", 99, '男', "学习KT语言") {println("显示结果:$it")}// 具名函数 showResultImplshowPersonInfo("wangwu", 89, '女', "学习C++语言", ::showResultImpl)
}fun showResultImpl(result: String) {println("显示结果:$result")
}inline fun showPersonInfo(name: String, age: Int, sex: Char, study: String, showResult: (String) -> Unit) {val str = "name:$name, age:$age, sex:$sex, study:$study"showResult(str)
}

Java写法

interface IShowResult { // 接口的折中方案 解决 kt的lambda问题void result(String result);
}// TODO 34.Kotlin语言的匿名函数与具名函数
public class KtBase34 {public static void main(String[] args) { // psv// 匿名函数 - 匿名接口实现showPersonInfo("lisi", 99, 'm', "study cpp", new IShowResult() {@Overridepublic void result(String result) {System.out.println("显示结果:" + result);}});// 具名函数 - 具名接口实现 showResultImplIShowResult showResultImpl = new MshowResultImpl();showPersonInfo("wangwu", 88, 'n', "study kt", showResultImpl);}static class MshowResultImpl implements IShowResult {@Overridepublic void result(String result) {System.out.println("显示结果:" + result);}}static void showPersonInfo(String name, int age, char sex, String study, IShowResult iShowResult) {String str = String.format("name:%s, age:%d, sex:%c, study:%s", name, age, sex, study);iShowResult.result(str);}
}

13.操作符

1.let

fun main() {var name: String? = nullname = "Derry"name = ""// name是可空类型的 如果真的是null,?后面这一段代码不执行,就不会引发空指针异常val r =name?.let {// it == name 本身// 如果能够执行到这里面的,it 一定不为nullif (it.isBlank()) { // 如果name是空值 "" 没有内容"Default"} else {"[$it]"}}println(r)
}
// 普通方式 对集合第一个元素相加
// let方式 对集合第一个元素相加
// 普通方式 对值判null,并返回
// let方式 对值判null,并返回
fun main() {// 普通方式 对集合第一个元素相加val list = listOf(6, 5, 2, 3, 5, 7)val value1 = list.first() // 第一个元素val result1 = value1 + value1println(result1) //12// let方式 对集合第一个元素相加val result2 = listOf(6, 5, 2, 3, 5, 7).let {// it == list集合it.first() + it.first() // 匿名函数的最后一行,作为返回值,let的特点,   但是前面学的apply永远是返回info本身/*truetruetrue*/}println(result2) //12println()// 普通方式 对值判null,并返回println(getMethod1(/*null*/ "Derry")) // let方式 + 空合并操作符 对值判null,并返回println(getMethod3(/*null*/ "Derry"))
}// 普通方式 对值判null,并返回
fun getMethod1(value: String?) : String {return if (value == null) "你传递的内容是null" else "欢迎回来${value}非常欢迎"
}
// 普通方式 简化版本
fun getMethod2(value: String?) = if (value == null) "你传递的内容是null" else "欢迎回来${value}非常欢迎"// let方式 + 空合并操作符 对值判null,并返回
fun getMethod3(value: String?) : String {return value?.let {"欢迎回来${it}非常欢迎"} ?: "你传递的内容是null"
}// let方式 + 空合并操作符 对值判null,并返回 简化版本
fun getMethod4(value: String?) =value?.let {"欢迎回来${it}非常欢迎"} ?: "你传递的内容是null"

2. ?: 空合并操作符

fun main() {var info: String? = "李小龙"// info = null// 空合并操作符  xxx ?: "原来你是null啊" // "如果xxx等于null,就会执行 ?: 后面的区域"println( info ?: "原来你是null啊" )// let函数 + 空合并操作符println(info?.let { "【$it】" } ?: "原来你是null啊2")
}

3.自定义异常

fun main() {try {var info: String? = nullcheckException(info)println(info!!.length)}catch (e: Exception) {println("啊呀:$e")}
}fun checkException(info: String?) {info ?: throw CustomException()
}class CustomException : IllegalArgumentException("你的代码太不严谨了")

4.先决条件函数

fun main() {var value1: String ? = nullvar value2: Boolean = false// 经常使用来检测是否为null// checkNotNull(value1) // java.lang.IllegalStateException: Required value was null.// requireNotNull(value1) // java.lang.IllegalArgumentException: Required value was null.// 经常使用来检测是否为truerequire(value2) // java.lang.IllegalArgumentException: Failed requirement.
}

5.substring

const val INFO = "Derry is Success Result"// TODO 43.Kotlin语言的substring
fun main() {val indexOf = INFO.indexOf('i')println(INFO.substring(0, indexOf)) //Derry println(INFO.substring(0 until indexOf)) // Derry  KT基本上用此方式: 0 until indexOf
}

6.split

fun main() {val jsonText = "Derry, Leo, Lance, Alvin"// list 自动类型推断成 list == List<String>val list = jsonText.split(",")// 直接输出 list 集合,不解构println("$list") //[Derry, Leo, Lance, Alvin]// C++ 有解构  Kt也有解构val (v1, v2, v3, v4) = listprintln("v1:$v1, v2:$v2, v3:$v3, v4:$v4") // v1:Derry, v2:Leo, v3:Lance, v4:Alvin
}

7.replace

fun main() {val sourcePwd = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"println("原始密码是:$sourcePwd")// 加密操作:就是把字符替换成数字 打乱了,就属于加密了val newPwd = sourcePwd.replace(Regex("[AKMNO]")) {it.value // 完全没有做任何事情when(it.value) { // 这里的每一个字符 A B C D ..."A" -> "9""K" -> "3""M" -> "5""N" -> "1""O" -> "4"else -> it.value // 就啥事不做,直接返回 字符本身 A B C D ...}}println("加密后的密码是:$newPwd") // 9BCDEFGHIJ3L514PQRSTUVWXYZ
}

8. ==跟 ===的区别

fun main() {// == 值 内容的比较  相当于Java的equals// === 引用的比较val name1 : String = "Derry"val name2 : String = "Derry"val name3 = "ww"// 小结:name1.equals(name2)  等价于 name1 == name2  都是属于 值 内容的比较println(name1.equals(name2)) // true,javaprintln(name1 == name2) // true,kt// 引用的比较println(name1 === name2) // trueprintln(name1 === name3) // false// 引用的比较 难度高一点点val name4 = "derry".capitalize() // 修改成"Derry"println(name4 === name1) // false
}

9.字符串遍历forEach

fun main() {val str = "ABCDE"str.forEach {  c -> // 覆盖默认的it参数名,修改参数名为 c// it == str的每一个字符 A B C D ...// print("$it  ")print("$c  ") //A  B  C  D  E}
}

10.toInt(),toIntOrNull()

// 小结:以后字符串有整形相关的转换,尽量用 toIntOrNull 此函数
fun main() {val number: Int = "666".toInt()println(number) //666// 字符串里面放入了Double类型,无法转换成Int,会奔溃// val number2: Int = "666.6".toInt()// println(number2)// 解决什么奔溃的问题val number2: Int? = "666.6".toIntOrNull()println(number2) //nullval number3: Int? = "888".toIntOrNull()println(number3) //888val number4: Int? = "888.8".toIntOrNull()println(number4 ?: "原来你是null啊")
}

11.roundToInt()

fun main() {println(65.4645654.toInt()) // 65 println(65.8343433.roundToInt()) // 65println(65.4645654.roundToInt())  // 65 四舍五入println(65.8343433.roundToInt()) // 66 四舍五入// 结论:用 roundToInt()函数,保证 Double ->转Int 持有四舍五入的效果// r的类型: Stringval r  = "%.3f".format(65.8343433)println(r) //65.834
}

12.apply、

特点:持有this,本身作为返回值

fun main() {val info = "Derry You Hao"// 普通的方式println("info字符串的长度是:${info.length}") //13println("info最后一个字符是:${info[info.length -1]}") //oprintln("info全部转成小写是:${info.toLowerCase()}") //derry you haoprintln()// apply内置函数的方式// info.apply特点:apply函数始终是返回 info本身 String类型val infoNew : String = info.apply {// 一般大部分情况下,匿名函数,都会持有一个it,但是apply函数不会持有it,却会持有当前this == info本身println("apply匿名函数里面打印的:$this") //Derry You Haoprintln("info字符串的长度是:${length}") //13println("info最后一个字符是:${this[length -1]}") //oprintln("info全部转成小写是:${toLowerCase()}") //derry you hao}println("apply返回的值:$infoNew") //Derry You Haoprintln()// 真正使用apply函数的写法规则如下:// info.apply特点:apply函数始终是返回 “本身”,所以可以链式调用info.apply {println("长度是:$length") //13}.apply {println("最后一个字符是:${this[length -1]}") //otruetruetrue}.apply {println("全部转成小写是:${toLowerCase()}") //derry you hao}println()// 普通写法val file = File("D:\\a.txt")file.setExecutable(true)file.setReadable(true)println(file.readLines())println()// apply写法// 匿名函数里面 持有的this == file本身/*val fileNew: File =*/ file.apply {setExecutable(true)}.apply {setReadable(true)}.apply {println(file.readLines())}
}

13.also、apply、let、run、with、takeIf、takeUnless

also:持有it,本身作为返回值
apply:持有this,本身作为返回值
let: 持有it,最后一行作为返回值
run:持有this,最后一行作为返回值
with:持有this,最后一行作为返回值
takeIf:持有it,如果为真返回本身,否则返回null
takeUnless:持有it,如果为假返回本身,否则返回null

fun main(args: Array<String>) {
// 普通方式 对集合第一个元素相加val list = listOf(6, 5, 2, 3, 5, 7)val value1 = list.first() // 第一个元素val result1 = value1 + value1println(result1)//12// let方式 对集合第一个元素相加val result2 = listOf(6, 5, 2, 3, 5, 7).let {// it == list集合it.first() + it.first() // 匿名函数的最后一行,作为返回值,let的特点,   但是前面学的apply永远是返回info本身/*truetruetrue*/}println(result2)//12println()// 普通方式 对值判null,并返回println(getMethod1(/*null*/ "Derry"))//欢迎回来Derry非常欢迎// let方式 + 空合并操作符 对值判null,并返回println(getMethod3(/*null*/ "Derry"))//欢迎回来Derry非常欢迎
}// 普通方式 对值判null,并返回
fun getMethod1(value: String?) : String {return if (value == null) "你传递的内容是null,你在搞什么飞机" else "欢迎回来${value}非常欢迎"
}
// 普通方式 简化版本
fun getMethod2(value: String?) = if (value == null) "你传递的内容是null,你在搞什么飞机" else "欢迎回来${value}非常欢迎"// let方式 + 空合并操作符 对值判null,并返回
fun getMethod3(value: String?) : String {return value?.let {"欢迎回来${it}非常欢迎"} ?: "你传递的内容是null,你在搞什么飞机"
}// let方式 + 空合并操作符 对值判null,并返回 简化版本
fun getMethod4(value: String?) =value?.let {"欢迎回来${it}非常欢迎"} ?: "你传递的内容是null,你在搞什么飞机"

14.run

特点:持有this,最后一行作为返回值

fun main() {val str = "Derry is OK"val r1 : Float = str.run {// this == str本身true5435.5f}println(r1)// 下面是 具名函数 配合 run函数str.run(::isLong) // this == str本身.run(::showText) // this == isLong返回的boolean值.run(::mapText).run(::println)println()// let函数持有it,run函数持有this 都可以很灵活的,把上一个结果值 自动给 下一个函数str.let(::isLong) // it == str本身.let(::showText) // it == isLong返回的boolean值.let(::mapText) // it == str本身.let(::println) // it == str本身println()// >>>>>>>>>>>>>>>>>>>>>> 上面全部都是具名函数调用给run执行  下面全部是 匿名函数调用给run执行str.run {if (length > 5) true else false}.run {if (this) "你的字符串合格" else "你的字符串不合格"}.run {"【$this】"}.run {println(this)}
}fun isLong(str: String) /* : Boolean */ = if (str.length > 5) true else falsefun showText(isLong: Boolean) /*: String */ = if (isLong) "你的字符串合格" else "你的字符串不合格"fun mapText(getShow: String) /*: String */ = "【$getShow】"

15.with

特点同run,持有this,最后一行作为返回值

fun main() {val str = "李元霸"// 具名操作/*with(str) {this == str本身}*/val r1 = with(str, ::getStrLen)//3val r2 = with(r1, ::getLenInfo)//你的字符串长度是:3val r3 = with(r2, ::getInfoMap)//【你的字符串长度是:3】with(r3, ::show)//【你的字符串长度是:3】println()// 匿名操作with(with(with(with(str) {length}) {"字符串长度是:$this"}){"【$this】"}){println(this)//【字符串长度是:3】}
}fun getStrLen(str: String) = str.length
fun getLenInfo(len: Int) = "你的字符串长度是:$len"
fun getInfoMap(info: String) = "【$info】"
fun show(content: String) = println(content)

16.also

持有it,本身作为返回值。类似apply,但apply持有this

fun main() {val str = "ABC"// 真正使用also函数的写法规则如下:// str.also特点:also函数始终是返回 “str本身”,所以可以链式调用str.also {println("str的原始数据是:$it") //ABC}.also {println("str转换小写的效果是:${it.toLowerCase()}") //abc}.also {println("结束了")}

17.takeIf

持有it,如果为真返回本身,否则返回null

fun main() {// name.takeIf { true/false }// true: 直接返回name本身// false: 直接返回null// 真正的用途println(checkPermissionAction2("Root", "!@#$"))// 小结:一般大部分情况下,都是 takeIf + 空合并操作符 = 一起使用
}// 前端
public fun checkPermissionAction(name: String, pwd: String) : String? {return name.takeIf { permissionSystem(name, pwd) }
}// takeIf + 空合并操作符
public fun checkPermissionAction2(name: String, pwd: String) : String {return name.takeIf { permissionSystem(name, pwd) } ?: "你的权限不够"
}// 权限系统
private fun permissionSystem(username: String, userpwd: String) : Boolean {return if (username == "Root" && userpwd == "!@#$") true  else false
}

17.takeUnless

持有it,如果为假返回本身,否则返回null

class Manager {private var infoValue: String? = nullfun getInfoValue() /* : String? */ = infoValuefun setInfoValue(infoValue: String) {this.infoValue = infoValue}
}fun main() {val manager = Manager()/*"Derry".takeIf { *//*it == "Derry"*//* }"Derry".takeUnless { *//*it == "Derry"*//* }*/// manager.setInfoValue("AAA")// 小结:takeUnless+it.isNullOrBlank() 一起使用,可以验证字符串有没有初始化等功能val r  = manager.getInfoValue().takeUnless { it.isNullOrBlank() } ?: "未经过任何初始化值"println(r)
}

14.集合

1.listOf(),getOrNull,getOrElse;setOf(),elementAtOrElse,elementAtOrNull

fun main() {val list = listOf("Derry", "Zhangsan", "Lisi", "Wangwu")// 取值:1.list[0],内部用的get(0)2.list.get(0)3.list.getOrElse(4){"你越界了"} 4.list.getOrNull(4) ?: "你越界了哦"5.set.elementAt(0)6.set.elementAtOrElse(4){"你越界了"} 7.set.elementAtOrNull(4) ?: "你越界了哦"val set: Set<String> = setOf("lisi", "wangwu", "zhaoliu", "zhaoliu") //set可以去重// 取值:1.set没有[0]这样的用法2.set.elementAt(0)3.set.elementAtOrElse4.set.elementAtOrNull
}

2.mutableListOf跟listOf的相互转换

fun main() {// 1.可变的集合,可add,可remove,toList()/toSet()变为不可变集合val mutableList = mutableListOf("Derry", "Zhangsna", "Wangwu")// 2.不可变集合,不可add,不可remove,toMutableList()/toMutableSet()变为可变集合val list = listOf(123, 456, 789)
}

3.+=,-=跟removeIf

fun main() {
// 1.mutator += -= 操作val list : MutableList<String> = mutableListOf("Derry", "DerryAll", "DerryStr", "Zhangsan")list += "李四" // mutator的特性 +=  -+ 其实背后就是 运算符重载而已list += "王五"list -= "Derry"println(list) //[DerryAll, DerryStr, Zhangsan, 李四, 王五]// 2.removeIf// list.removeIf { true } // 如果是true 自动变量整个可变集合,进行一个元素一个元素的删除list.removeIf { it.contains("Derr") } // 过滤所有的元素,只要是有 Derr 的元素,就是true 删除println(list) //[Zhangsan, 李四, 王五]
}

3.list遍历

fun main() {val list = listOf(1, 2, 3, 4, 5, 6, 7)// 第一种 遍历方式:for (i in list) {print("$i  ") //1  2  3  4  5  6  7}println()// 第二种 遍历方式:list.forEach {// it == 每一个元素print("$it  ") //1  2  3  4  5  6  7}println()// 第三种 遍历方式:list.forEachIndexed { index, item ->print("下标:$index, 元素:$item    ") //下标:0, 元素:1    下标:1, 元素:2    下标:2, 元素:3    下标:3, 元素:4    下标:4, 元素:5    下标:5, 元素:6    下标:6, 元素:7}
}

4.解构语法过滤元素

// 1.集合配合解构语法
// 2.反编译看Java给三个变量赋值的代码
// 3.解构屏蔽接收值
fun main() {val list: List<String> = listOf("李元霸", "李小龙", "李连杰")val(value1, value2, value3) = list//val表示只读的,不能赋值;赋值可以使用varprintln("value1:$value1, value2:$value2, value3:$value3")// 用_可以不接收赋值,可以节约一点性能val(_ , n2, n3) = list// println(_) _不是变量名,是用来过滤解构赋值的,不接收赋值给我println("n2:$n2, n3:$n3")
}

5.list去重

  list.toSet()list.toSet().toList()list.distinct() //快捷函数,内部 list.toMutableSet().toList()

6.kotlin数组类型

 Kotlin语言中的各种数组类型,虽然是引用类型,背后可以编译成Java基本数据类型IntArray        intArrayOfDoubleArray     doubleArrayOfLongArray       longArrayOfShortArray      shortArrayOfByteArray       byteArrayOfFloatArray      floatArrayOfBooleanArray    booleanArrayOfArray<对象类型>           arrayOf         对象数组// 2.elementAtOrElse elementAtOrNull
// 3.List集合转 数组:toIntArray,toDoubleArray等
// 4.arrayOf        Array<File>

7.map

1.创建
val mMap1 = mapOf("Derry" to 534.4, "Kevin" to 454.5)
val mMap2 = mapOf(Pair("Derry", 545.4), Pair("Kevin", 664.4))
两种方式等价2.读取
mMap["Derry"] //内部 mMap.get("Derry"),找不到会返回null,不会崩溃
mMap.getOrDefault("Derry", -1)
mMap.getOrElse("Derry") {-1}
mMap.getValue("Derry") //不推荐,找不到会崩溃3.遍历
map.forEach {// it 内容 每一个元素 (K 和 V)  每一个元素 (K 和 V)  每一个元素 (K 和 V)// it 类型  Map.Entry<String, Int>println("K:${it.key} V:${it.value}")
}for (item in map) {println("key:${item.key} value:${item.value}")
}修改key、value变量名
map.forEach { (k, v) ->println("key:$k, value:$v")
}4.可变集合操作: += [] put
val map : MutableMap<String, Int> = mutableMapOf(Pair("Derry", 123), "Kevin" to 456, Pair("Dee", 789))// 下面是可变操作map += "AAA" to 111map -= "Kevin"map["CCC"] = 888 //等于map.put("DDD", 888),put 和 [] 等价的map.getOrPut("FFF") { 555 } //有就取FFF的值 ,没有就把555加进去

15.类

1.Bean类

class KtBase70 {var info = "abcdefg ok is success" //注意:如果是val,则只能取值,不能赋值
//    如果需要修改get,set方法
//    get() = field.capitalize() // 把首字母修改成大写
//    set(value) {
//        field = "**【$value】**"
//    }// 计算属性  下面这样写 get函数覆盖了 field 内容本身,number2就属于计算属性了val number2 : Int //由于get覆盖了field,此处不能赋值get() = (1..1000).shuffled().first() // 从1到1000取出随机值 返回给 getNumber2()函数为什么没有看到 number2 属性定义?答:因为属于 计算属性 的功能,根本在getNumber2函数里面,就没有用到 number2属性,所以 number2属性 失效了,无用了,以后用不到了// 防范竞态条件  当你调用可能为null或空值的成员时,就必须采用防范竞态条件var info: String ? = null // ""fun getShowInfo() : String {return info?.let {if (it.isBlank()) {"info你原来是空值,请检查代码..."} else {"最终info结果是:$it"}} ?: "info你原来是null,请检查代码..."}}fun main() {val ktBase70 = KtBase70()ktBase70.info = "gsofis"println(ktBase70.name)
}

2.构造函数

class KtBase72(_name: String) {
//构造函数的参数不能直接用,但在init代码块可以直接使用
init {//主构造被调用时调用println("主构造函数被调用了 $_username")// 要求...,否则...require(username.isNotBlank()) { "你的username空空如也,异常抛出" }}//构造函数的参数不能直接用,需要重新赋值才能使用
var name = _name
//更好的方式:在参数前加上var或val,例如class KtBase72(var name: String) //次构造函数,必须要先调用主构造函数constructor(name: String, sex: Char) : this(name) {println("2个参数的次构造函数 name:$name, sex:$sex")}
}

3.lateinit延迟初始化

lateinit var responseResultInfo: String
//为了转成 kproperty对象,才能获取,是否已经初始化了
使用 if (::responseResultInfo.isInitialized) 判断是否初始化//普通方式(饿汉式 没有任何懒加载的特点)val databaseData1 = readSQlServerDatabaseAction()
//惰性加载val databaseData2 by lazy { readSQlServerDatabaseAction() }

4.open

 KT所有的类和方法,默认是final修饰的,不能被继承和重写,和Java相反。解决:在类和方法前面加open

5.is、as

is:是否是xxx实例
val p : Person3 = Student3("李四")
//if (p is Student3) {
//        p.methodStudent()//智能类型转换
//}(p as Student3).methodStudent()//这里已经转换了,所以下面可以调用子类的方法。否则不能调用p.methodStudent()

6.Any()

// 在KT中,所有的类,都隐士继承了 : Any(),默认就有
// Any类在KT设计中:只提供标准,你看不到实现,实现在各个平台处理好了

7.object单例

object KtBase87 {/* object 对象类背后做了什么事情public static final KtBase87 INSTANCE;private KtBase87() {} // 主构造废除一样的效果public final void show() {String var1 = "我是show函数...";...System.out.println(var1);}// 这个区域是 object 不同点:static {KtBase87 var0 = new KtBase87();INSTANCE = var0;String var1 = "KtBase91 init...";...System.out.println(var0);}*/init {println("KtBase91 init...")}fun show() = println("我是show函数...")
}fun main() {// object KtBase87 既是单例的实例,也是类名// 小结:既然是 单例的实例,又是类名,只有一个创建,这就是典型的单例println(KtBase87) // 背后代码:println(KtBase87.INSTANCE)// 背后代码:KtBase87.INSTANCE.show();println(KtBase87.show())
}

8.对象表达式

interface RunnableKT {fun run()
}open class KtBase88 {open fun add(info: String) = println("KtBase88 add:$info")open fun del(info: String) = println("KtBase88 del:$info")
}class KtBase88Impl : KtBase88() {override fun add(info: String) {// super.add(info)println("我是具名对象 add:$info")}override fun del(info: String) {// super.del(info)println("我是具名对象 del:$info")}
}fun main() {
// 具名实现方式val p2 = KtBase88Impl()p2.add("刘一")p2.del("刘二")// 匿名对象 表达式方式val p = object : KtBase88() {override fun add(info: String) {// super.add(info)println("我是匿名对象 add:$info")}override fun del(info: String) {// super.del(info)println("我是匿名对象 del:$info")}}p.add("李元霸")p.del("李连杰")// 对Java的接口 用   Java最简洁的方式 方式二val p4 = Runnable {println("Runnable run2 ...")}p4.run()// 对Java的接口 用   KT[对象表达式方式]  方式一val p3 = object : Runnable {override fun run() {println("Runnable run ...")}}p3.run()// 对KT的接口 用   KT[对象表达式方式]  方式一val p5 = object : RunnableKT {override fun run() {println("RunnableKT 方式一 run ...")}}p5.run()// 对KT的接口 用   Java最简洁的方式 方式二//kt没有这种方式
//    RunnableKT {
//
//    }// 小结:Java接口,有两种方式 1(object : 对象表达式)  2简洁版,
//       KT接口,只有一种方式 1(object : 对象表达式)
}

9.伴生对象

class KtBase89 {// 伴生对象companion object {val info = "DerryINfo"fun showInfo() = println("显示:$info")val name = "Derry"}/* companion object {} 背后的逻辑private static final String name = "Derry";private static final String info = "DerryINfo";public static final KtBase89.Companion Companion = new KtBase89.Companion(xxx);public static final class Companion {@NotNullpublic final String getInfo() {return KtBase89.info;}@NotNullpublic final String getName() {return KtBase89.name;}public final void showInfo() {String var1 = "显示:" + ((KtBase89.Companion)this).getInfo();boolean var2 = false;System.out.println(var1);}private Companion() {}// $FF: synthetic methodpublic Companion(DefaultConstructorMarker $constructor_marker) {this();}}*/
}// 伴生对象的由来: 在KT中是没有Java的这种static静态,伴生很大程度上和Java的这种static静态 差不多的
// 伴生对象只会初始化一次
fun main() {// 背后代码:System.out.println(KtBase89.Companion.getInfo())println(KtBase89.info)// 背后代码:System.out.println(KtBase89.Companion.getName())println(KtBase89.name)// 背后代码:KtBase89.Companion.showInfo()KtBase89.showInfo()
}

10.嵌套类、内部类

// 默认情况下:就是嵌套类关系
// 嵌套类特点:外部的类 能访问 内部的嵌套类
//           内部的类 不能访问 外部类的成员// 内部类(inner class)的特点: 内部的类 能访问 外部的类
//              外部的类 能访问 内部的类class Outer {val info: String  = "OK"fun show() {Nested().output()}class Nested {fun output() = println("嵌套类")}
}class Body(_bodyInfo: String) { // 身体类val bodyInfo = _bodyInfofun show() {Heart().run()}inner class Heart { // 心脏类fun run() = println("心脏访问身体信息:$bodyInfo")}
}fun main() {// 嵌套类:Outer.Nested().output()// 内部类:Body("isOK").Heart().run()
}

11.普通类、数据类

// 普通类
class ResponseResultBean1(var msg: String, var code: Int, var data: String) : Any()
// set get 构造函数// TODO 99-数据类使用条件
// 条件一:数据类至少必须有一个参数的主构造函数,参数必须有var或val修饰
// 条件二:数据类不能使用 abstract,open,sealed,inner 等等 修饰 (数据类,只是做数据载入和数据存储的事情)
// 条件三:需求:比较,copy,toString,解构,等等这些丰富的功能时,也可以使用数据类data class ResponseResultBean2(var msg: String, var code: Int, var data: String) : Any()
// set get 构造函数 解构操作 copy 重写toString hashCode equals  数据类 生成 更丰富println(ResponseResultBean1("loginSuccess", 200, "登录成功的数据..."))
// 普通类:: Any() toString Windows实现打印了   com.derry.s5.ResponseResultBean1@266474c2println(ResponseResultBean2("loginSuccess", 200, "登录成功的数据..."))
// 数据类:: Any() 默认重写了 父类的 toString  打印子类的toString详情  ResponseResultBean2(msg=loginSuccess, code=200, data=登录成功的数据...)== 值的比较,相当于java的equals.
println(ResponseResultBean1("loginSuccess", 200, "登录成功的数据...") ==ResponseResultBean1("loginSuccess", 200, "登录成功的数据..."))// false,Any父类的 equals 实现 (ResponseResultBean1对象引用 比较 ResponseResultBean1对象引用)println(ResponseResultBean2("loginSuccess", 200, "登录成功的数据...") ==ResponseResultBean2("loginSuccess", 200, "登录成功的数据..."))// true,Any父类的 equals 被 数据类 重写了 equals 会调用 子类的 equals函数(对值的比较)

12.copy函数

data class KtBase92 (var name: String, var age: Int) // 主构造
{var coreInfo : String = ""init {println("主构造被调用了")}// 次构造constructor(name: String) : this(name, 99) {println("次构造被调用")coreInfo = "增加非常核心的内容信息"}override fun toString(): String {return "toString name:$name, age:$age, coreInfo:$coreInfo"}
}/* 生成的toString 为什么只有两个参数?答:默认生成的toString 或者 hashCode equals 等等... 主管主构造,不管次构造public String toString() {return "KtBase92(name=" + this.name + ", age=" + this.age + ")";}*/fun main() {val p1 = KtBase92("李元霸") // 调用次构造初始化对象println(p1)
//主构造被调用了
//次构造被调用
//toString name:李元霸, age:99, coreInfo:增加非常核心的内容信息val newP2 = p1.copy("李连杰", 78)println(newP2)
//主构造被调用了
//toString name:李连杰, age:78, coreInfo:// copy toString hashCode equals 等等... 主管主构造,不管次构造// 注意事项:使用copy的时候,由于内部代码只处理主构造,所以必须考虑次构造的内容
}

13.解构

// 普通类
class Student1(var name: String , var age: Int, var sex: Char) {// 注意事项:不能是component0,顺序必须是 component1 component2 component3 和成员一一对应,顺序下来的operator fun component1() = nameoperator fun component2() = ageoperator fun component3() = sex
}
// 数据类
data class Student2Data(var name: String , var age: Int, var sex: Char)fun main() {val(name, age, sex) = Student1("李四", 89, '男')println("普通类 结构后:name:$name, age:$age, sex:$sex")//普通类 结构后:name:李四, age:89, sex:男val(name1, age1, sex1) = Student2Data("李四", 89, '男')println("数据类 结构后:name:$name1, age:$age1, sex:$sex1")//数据类 结构后:name:李四, age:89, sex:男val(_, age2, _) = Student1("李四", 89, '男')println("数据类 结构后: age2:$age2")//数据类 结构后: age2:89
}

14.运算符重载

class AddClass1(number1: Int, number2: Int)// 写一个数据类,就是为了,toString 打印方便而已哦
data class AddClass2(var number1: Int, var number2: Int) {operator fun plus(p1: AddClass2) : Int {return (number1 + p1.number1) + (number2 + p1.number2)}// 查看 整个KT可以用的  运算符重载 方式// operator fun AddClass2.
}fun main() {// C++语言  +运算符重载就行了  -运算符重载就行了// KT语言  plus代表+运算符重载println(AddClass2(1, 2) + AddClass2(3, 4))
}

15.枚举类

// KT想表达:枚举其实也是一个class,为什么,就是为了 枚举可以有更丰富的功能
enum class Week {星期一,//枚举主构造参数必须跟枚举参数一致星期二,星期三,星期四,星期五,星期六,星期日;//分号表示结束枚举
}
//======================================================
// 四肢信息class,我就是为了方便toString打印
data class LimbsInfo (var limbsInfo: String, var length: Int) {fun show() {println("${limbsInfo}的长度是:$length")}
}enum class Limbs(private var limbsInfo: LimbsInfo) {LEFT_HAND(LimbsInfo("左手", 88)), //  枚举的 主构造的参数 必须和 枚举(的参数) 保持一致RIGHT_HAND(LimbsInfo("右手", 88)), // 右手LEFT_FOOT(LimbsInfo("左脚", 140)), // 左脚RIGHT_FOOT(LimbsInfo("右脚", 140)); // 右脚,分号表示结束枚举fun show() = "四肢是:${limbsInfo.limbsInfo}的长度是:${limbsInfo.length}"fun updateData(limbsInfo: LimbsInfo) {println("更新前的数据是:${this.limbsInfo}")this.limbsInfo.limbsInfo = limbsInfo.limbsInfothis.limbsInfo.length = limbsInfo.lengthprintln("更新后的数据是:${this.limbsInfo}")}
}
//====================================================
代数类型数据
enum class Exam {Fraction1, // 分数差Fraction2, // 分数及格Fraction3, // 分数良好Fraction4; // 分数优秀// 需求 得到优秀的孩子姓名var studentName: String? = null// 我们用枚举类,要做到此需求,就非常的麻烦了,很难做到而已,不是做不到//  需求:引出 密封类
}class Teacher (private val exam: Exam) {fun show() =when (exam) {Exam.Fraction1 -> "该学生分数很差"Exam.Fraction2 -> "该学生分数及格"Exam.Fraction3 -> "该学生分数良好"Exam.Fraction4 -> "该学生分数优秀"// else -> 由于我们的show函数,是使用枚举类类型来做判断处理的,这个就属于 代数数据类型,就不需要写 else 了// 因为when表达式非常明确了,就只有 四种类型,不会出现 else 其他,所以不需要写}
}// TODO 95-Kotlin语言的枚举类学习
fun main() {println(Week.星期一)//星期一// 枚举的值 等价于 枚举本身println(Week.星期二 is Week)//true// 一般的用法如下:println(Limbs.LEFT_HAND.show())Limbs.RIGHT_HAND.updateData(LimbsInfo("右手2", 99))println(Teacher(Exam.Fraction1).show())
}

16.密封类

// 密封类,成员必须有类型,并且继承本类
sealed class Exams {// object? Fraction1 Fraction3 都不需要任何成员,所以一般都写成object,单例就单例,无所谓了object Fraction1 : Exams() // 分数差object Fraction2 : Exams() // 分数及格object Fraction3 : Exams() // 分数良好// 假设 Fraction4 是可以写object的,那么也不合理,因为对象不是单例的,有 对象1李四 对象2王五class Fraction4(val studentName : String) : Exams() // 分数优秀// 需求 得到优秀的孩子姓名// var studentName: String? = null// 我们用枚举类,要做到此需求,就非常的麻烦了,很难做到而已,不是做不到//  需求:引出 密封类
}class Teachers (private val exam: Exams) {fun show() =when (exam) {is Exams.Fraction1 -> "该学生分数很差"is Exams.Fraction2 -> "该学生分数及格"is Exams.Fraction3 -> "该学生分数良好"is Exams.Fraction4 -> "该学生分数优秀:该学生的姓名是:${(this.exam as Exams.Fraction4).studentName}"}
}// TODO 98-Kotlin语言的密封类学习
fun main() {println(Teachers(Exams.Fraction1).show())println(Teachers(Exams.Fraction4("王五")).show()) // 对象2println(Exams.Fraction1 === Exams.Fraction1) // true, === 比较对象引用, object是单例 只会实例化一次println(Exams.Fraction4("AAA") === Exams.Fraction4("AAA")) // class 有两个不同的对象,所以是false
}

16.接口

1.接口定义

// TODO 100-Kotlin语言的接口定义
// 1.接口里面的所有成员 和 接口本身 都是 public open 的,所以不需要open,这个是接口的特殊
// 2.接口不能有主构造,反正就是没有构造
// 3.实现类要重写接口函数和接口成员,且要加override关键字来修饰interface IUSB {var usbVersionInfo: String // USB版本相关的信息var usbInsertDevice: String // USB插入的设备信息fun insertUBS() : String
}// 第一种方式:鼠标UBS实现类
class Mouse(override var usbVersionInfo: String = "USB 3.0", override var usbInsertDevice: String = "鼠标接入了UBS口") :IUSB {override fun insertUBS() = "Mouse $usbVersionInfo, $usbInsertDevice"
}// 第二种方式:键盘USB实现类
class KeyBoard : IUSB {override var usbVersionInfo: String = "USB 3.1"// 下面的 set get 都会持有 field,现在是你没有给 usbVersionInfo 赋值, 意味着field是没法让set/get持有的get() = fieldset(value) {field = value}override var usbInsertDevice: String = "键盘接入了UBS口"get() {println("@你get了[${field}]值出去了")return field}set(value) {field = valueprintln("@你set了[${value}]值进来了")}override fun insertUBS(): String = "KeyBoard $usbVersionInfo, $usbInsertDevice"
}fun main() {val iusb1 : IUSB = Mouse()println(iusb1.insertUBS()) //Mouse USB 3.0, 鼠标接入了UBS口println()val iusb2: IUSB = KeyBoard()println(iusb2.insertUBS()) //@你get了[键盘接入了UBS口]值出去了//KeyBoard USB 3.1, 键盘接入了UBS口iusb2.usbInsertDevice = "AAA" //@你set了[AAA]值进来了
}

2.修改接口的默认实现

interface USB2 {// 1.接口 var 是不能直接给接口成员赋值的 (但是有其他办法get())// 2.任何类 接口 等等  val 代表只读的,是不可以在后面动态赋值 (也有其他办法)// TODO 101-Kotlin语言的接口的默认实现
// 1.注意:这样做是不建议的,因为接口成员本来就是用来声明标准的
//        但是可以在接口成员声明时,完成对接口成员的实现val usbVersionInfo: String // USB版本相关的信息get() = (1..100).shuffled().last().toString()// 因为是val 不能写setval usbInsertDevice: String // USB插入的设备信息get() = "高级设备接入USB"// val 不需要setfun insertUBS() : String
}// 鼠标UBS实现类
class Mouse2 : USB2 {override val usbInsertDevice: Stringget() = super.usbInsertDeviceoverride val usbVersionInfo: Stringget() = super.usbVersionInfooverride fun insertUBS() = "Mouse $usbVersionInfo, $usbInsertDevice"
}fun main() {val iusb1 = Mouse2()println(iusb1.insertUBS()) //Mouse 70, 高级设备接入USB,随机打印
}

3.抽象类

abstract class BaseActivity {fun onCreate() {setContentView(getLayoutID())initView()initData()initXXX()}private fun setContentView(layoutID: Int) = println("加载{$layoutID}布局xml中")abstract fun getLayoutID(): Intabstract fun initView()abstract fun initData()abstract fun initXXX()
}class LoginActivity : BaseActivity() {override fun getLayoutID(): Int = 564override fun initView() = println("做具体初始化View的实现")override fun initData() = println("做具体初始化数据的实现")override fun initXXX() = println("做具体初始化XXX的实现")fun show() {super.onCreate()}
}// TODO 102-Kotlin语言的抽象类学习
fun main() = LoginActivity().show()
//加载{564}布局xml中
//做具体初始化View的实现
//做具体初始化数据的实现
//做具体初始化XXX的实现

4.泛型

  1. Java SE 1.5的才有的特性,本质是参数化类型,泛型分为泛型类泛型接口泛型方法
    在没有泛型的情况的下只能通过对Object 的引用来实现参数的任意化
    没泛型的缺点:要显式的强制类型转换,而强制转换在编译期是不做检查的,容易把问题留到运行时
    泛型优点:在编译时检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率,避免在运行时出现 ClassCastException

  2. 泛型实现原理:泛型擦除
    编译器在编译期对字节码时先进行类型检查,再进行类型擦除所有泛型类型相关信息(即所有类型参数都用限定类型替换,包括类、变量和方法。如果类型变量有限定则原始类型就用第一个边界的类型来替换,譬如 class Test<T extends Comparable & Serializable> {} 的原始类型就是 Comparable),即运行时就不存在任何泛型类型相关的信息

    fun test() {val mList= ArrayList<String>() //List<Integer> 在运行时仅用一个 List 来表示,这样做的目的是为了和 Java 1.5 之前版本进行兼容mList.add("123") //实际上是"123"作为Object存入集合中的Log.v("tag",mList[0]) //从list实例中读取出来Object然后转换成String之后才能使用}
    
  3. inline
    inline函数中我们可以指定类型不被擦除, 因为inline函数在编译期会将字节码copy到调用它的方法里,所以编译器会知道当前的方法中泛型对应的具体类型是什么,然后把泛型替换为具体类型,从而达到不被擦除的目的,在inline函数中我们可以通过reified关键字来标记这个泛型在编译时替换成具体类型。

    思考:我们在用Gson解析json数据的时候,是如何解析数据拿到泛型类型 Bean 结构的?
    TypeToken 是一种方案,可以通过getType() 方法获取到我们使用的泛型类的泛型参数类型,不过采用反射解析的时候,Gson构造对象实例时调用的是默认无参构造方法,所以依赖 Java 的 Class 字节码中存储的泛型参数信息,Java 的泛型机制虽然在编译期间进行了擦除,但是Java 在编译时会在字节码里指令集以外的地方保留部分泛型的信息,接口、类、方法定义上的所有泛型、成员变量声明处的泛型都会被保留类型信息,其他地方的泛型信息都会被擦除,这些信息被保存在 class 字节码的常量池中,使用泛型的代码处会生成一个 signature 签名字段,通过签名 signature 字段指明这个常量池的地址,JDK 提供了方法去读取这些泛型信息的方法,利用反射就可以获得泛型参数的具体类型,譬如:

    (mList.javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0]
    

    一般json解析

    inline fun <reified T> Gson.fromJson(jsonStr: String) = fromJson(json, T::class.java)
    
  4. reified
    在inline函数中通过reified关键字来标记这个泛型在编译时替换成具体类型

  5. 泛型使用示例
    Kotlin的泛型类型推断功能还有一种最有用的地方,就是根据不同泛型类型调用不同的方法这种场景

        //bundle 存值fun <T> putBundleValue(key: String, value: T) {when (value) {is Int -> bundle.putInt(key, value)is Long -> bundle.putLong(key, value)is String -> bundle.putString(key, value)is Boolean -> bundle.putBoolean(key, value)else -> throw  Exception("不支持的类型")}}//bundle 取值inline fun <reified T> getBundleValue(key: String): T {return when (T::class.java) {java.lang.Integer::class.java -> bundle.getInt(key) as Tjava.lang.Long::class.java -> bundle.getLong(key) as Tjava.lang.String::class.java -> bundle.getString(key) as Tjava.lang.Boolean::class.java -> bundle.getBoolean(key) as T//     注意不能写成以下形式,否则匹配不到类型,因为 reified 会推断为Java.lang包下的基本类型而不是kotlin包下的类型
    //     Int::class.java -> bundle.getInt(key) as T
    //     Long::class.java -> bundle.getLong(key) as T
    //     String::class.java -> bundle.getString(key) as T
    //     Boolean::class.java -> bundle.getBoolean(key) as Telse -> throw  Exception("不支持的类型")}}
    

    这样只用一个函数就能调用存取数据方便多了

    putValue("string", "hello")
    putValue("bool", true)val stringValue=getValue<String>("string")
    val booleanValue:Boolean = getValue("bool") //声明类型后泛型能自动推导
    

    补充一下: 如果限定泛型T为基本类型,其实也能这样投机取巧来实现

      //bundle 取值inline fun <reified T> getBundleValue(key: String): T {return when {0 is T -> bundle.getInt(key) as T  //判断T是否为Int1L is T-> bundle.getLong(key) as T //判断T是否为Long"h" is T -> bundle.getString(key) as T //判断T是否为String类型true is T -> bundle.getBoolean(key) as T //判断T是否为Boolean类型else -> throw  Exception("不支持的类型")}}
    
class KtBase103<T> (private val obj: T) { // 万能输出器fun show() = println("万能输出器:$obj")
}// TODO 103-Kotlin语言的定义泛型类
// 1.定义 对象输出器 println(obj)
// 2.定义两个对象,三个属性
// 3.对象 String Int Double Float Char 等 测试 对象输出器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() {val stu1 = Student("张三", 88, '男')val tea1 = Teacher("王五", 77, '男')KtBase103(stu1).show() //万能输出器:Student(name=张三, age=88, sex=男)KtBase103(tea1).show() //万能输出器:Teacher(name=王五, age=77, sex=男)KtBase103(String("刘一".toByteArray())).show() //万能输出器:刘一KtBase103(575).show() //万能输出器:575KtBase103(53456.45).show() //万能输出器:53456.45KtBase103(4645.5f).show() //万能输出器:4645.5KtBase103('男').show() //万能输出器:男
}

1.泛型类型变换

// 1.万能对象返回器 Boolean来控制是否返回 运用 takeIf
class KtBase104<T>(private val isTrue: Boolean, private val obj: T) {fun getObj() : T? = obj.takeIf { isTrue }
}
data class Teacher(val name: String , val age: Int, val sex: Char)// TODO 104-Kotlin语言的泛型函数学习
// 1.万能对象返回器 Boolean来控制是否返回 运用 takeIf
// 2.四个对象打印
// 3.对象打印 + run + ?:
// 4.对象打印 + apply + ?:
// 5.show(t: T) + apply + ?:
fun main() {val tea1 = Teacher("王五", 77, '男')println(KtBase104(true, tea1).getObj()) //Teacher(name=王五, age=77, sex=男)println(KtBase104(false, tea1).getObj() ?: "大哥,你万能对象返回器,是返回null啊") //大哥,你万能对象返回器,是返回null啊println()// 3.对象打印 + run + ?:val r : Any = KtBase104(true, tea1).getObj() ?.run {// 如果 getObj 返回有值,就会进来// this == getObj本身println("万能对象是:$this") // 返回Unit,万能对象是:Student(name=王五, age=77, sex=男)545.4f // 返回Float} ?: println("大哥,你万能对象返回器,是返回null啊") // 返回Unitprintln(r) //545.4println()// apply特点:永远都是返回 getObj.apply  getObj本身val r2 : Teacher = KtBase104(true, tea1).getObj().apply {  }!!println("r2:$r2") //r2:Student(name=王五, age=77, sex=男)// 4.对象打印 + apply + ?:val r3: Teacher = KtBase104(true, tea1).getObj() .apply {// this == getObj本身if (this == null) {println("r3大哥,你万能对象返回器,是返回null啊")} else {println("r3万能对象是:$this")}}!!println("r3:$r3")//r3万能对象是:Teacher(name=王五, age=77, sex=男)//r3:Teacher(name=王五, age=77, sex=男)println()show("Derry") //show万能对象是:Derryshow(null) //show,你万能对象返回器,是返回null啊println()show2("Derry")//show2,万能对象是:Derry//show2: 你传递进来的r:Derryshow2(null) //show2: 你传递进来的r:null
}// 5.show(t: T) + also + ?:
fun <B> show(item: B) {item ?.also {// it == item本身println("show万能对象是:$it")} ?: println("show,你万能对象返回器,是返回null啊")
}fun <B> show2(item: B) {// var r0 = itemvar r : B? = item ?.also {if (it == null) {println("show2,你万能对象返回器,是返回null啊")} else {println("show2,万能对象是:$it")}} ?: nullprintln("show2: 你传递进来的r:$r")
}

2.泛型配合lambda使用

// 1.类 isMap map takeIf  map是什么类型
class KtBase105<T>(val isMap: Boolean = false, val inputType: T) {// 模仿RxJava  T是要变化的输入类型   R是变换后的输出类型// 要去map返回的类型是 R?  == 有可能是R 有可能是nullinline fun <R> map(mapAction: (T) -> R) = mapAction(inputType).takeIf { isMap }
}inline fun <I, O> map(inputValue : I , isMap: Boolean = true, mapActionLambda : (I) -> O) = if (isMap) mapActionLambda(inputValue) else null// TODO 105-Kotlin语言的泛型变换实战
// 1.类 isMap map takeIf  map是什么类型
// 2.map int -> str 最终接收是什么类型
// 3.map per -> stu 最终接收是什么类型
// 4.验证是否是此类型 与 null
fun main() {// 2.map int -> str 最终接收是什么类型val p1 = KtBase105(isMap = /*true*/ false, inputType = 5434)val r = p1.map {it.toString() // lambda最后一行是 返回值"我的it是:$it" // lambda最后一行是 返回值}// 4.验证是否是此类型 与 nullprintln(r is String) //falseprintln(r is String?) //trueprintln(r ?: "大哥你是null,你在搞什么飞机...,你是不是传入了isMap是false") //大哥你是null,你在搞什么飞机...,你是不是传入了isMap是falseprintln()// 3.map per -> stu 最终接收是什么类型val p2 = KtBase105(true, Persons("李四", 99))val r2 : Students? = p2.map {// it == Persons对象 == inputTypeStudents(it.name, it.age)}println(r2) //Students(name=李四, age=99)println()// map函数 模仿RxJava变换操作val r3 = map(123) {it.toString()"map包裹[$it]" // lambda表达式最后一行,就是返回值}println(r3) //map包裹[123]
}data class Persons(val name: String, val age: Int)
data class Students(val name: String, val age: Int)

3.泛型类型约束<T : PersonClass>

open class MyAnyClass(name: String) // 祖宗类 顶级父类
open class PersonClass(name: String) : MyAnyClass(name = name) // 父类
class StudentClass(name: String) : PersonClass(name = name) // 子类
class DogClass(name: String) // 其他类 另类// TODO 106-Kotlin语言的泛型类型约束学习
// T : PersonClass相当于Java的 T extends PersonClass
// 约束了传入的参数只能是PersonClass及其子类
class KtBase106<T : PersonClass> (private val inputTypeValue: T, private val isR: Boolean = true) {// 万能对象返回器fun getObj() = inputTypeValue.takeIf { isR }
}fun main() {val any = MyAnyClass("Derry1")// 祖宗类 顶级父类val dog = DogClass("Derry1") // 其他类 另类val per = PersonClass("Derry1") // 父类val stu = StudentClass("Derry1") // 子类//    val r1 = KtBase106(any).getObj() // 提示报错了,因为类型限定了传入的参数只能是PersonClass及其子类
//    println(r1)//    val r5 = KtBase106(dog).getObj() // 提示报错了,因为类型限定了传入的参数只能是PersonClass及其子类
//    println(r5)val r2 = KtBase106(per).getObj()println(r2)val r3 = KtBase106(stu).getObj()println(r3)
}

4.vararg多参数

// TODO 107-Kotlin语言的vararg关键字(动态参数)
// 1.objectArray:Array<T>
// 2.showObj(index)
// 3.mapObj(index,变换lambda)
// 4.p.showOBj  p.mapObj(int -> str)
// 5.p的类型  it的类型
class KtBase107<T> (vararg objects : T, var isMap: Boolean) {// out 我们的T只能被读取,不能修改   T只能读取private val objectArray : Array<out T> = objects// 2.showObj(index)  "你${index}下标去的对象是null"fun showObj(index: Int) : T? = objectArray[index].takeIf { isMap } ?: null /*objectArray[index]*/// 3.mapObj(index, 变换lambda)   objectArray[index]fun <O> mapObj(index: Int, mapAction: (T?) -> O) = mapAction( objectArray[index].takeIf { isMap }  /*objectArray[index]*/ )
}fun main() {val p2 : KtBase107<String> = KtBase107("AAA", "BBB", "CCC", isMap = true)// 为什么 it 是 String ? , 是因为你的  lambda (T ?) -> O  T? 指定了 ?val r3 = p2.mapObj(2) {it// it 是什么类型 ?  String ?"我要把你变成String类型 it:$it"}println(r3) //我要把你变成String类型 it:CCC// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>//  由于使用了太多类型混合,所以真正类型是 : KtBase107<{Comparable<*> & java.io.Serializable}>//  由于不允许我们这样写,所以我们用父类 Any? 代替val p : KtBase107<Any?>  = KtBase107("Derry", false, 53454, 4543.3f, 4554.54, null, 'C', isMap = true)println(p.showObj(0))//Derryprintln(p.showObj(1))//falseprintln(p.showObj(2))//53454println(p.showObj(3))//4543.3println(p.showObj(4)) // 4554.54println(p.showObj(5)/*?.特殊操作 如果是null 会引发奔溃*/) // nullprintln(p.showObj(6)) // Cprintln()// mapObj// it类型 {Comparable<*> & java.io.Serializable}  需要转换一下才行 例如:it.toStringval r : Int = p.mapObj(0) {itit.toString()it.toString().length}println("第零个元素的字符串长度是:$r")//第零个元素的字符串长度是:5// it类型 {Comparable<*> & java.io.Serializable}  由于我们的第三个元素是 Int类型,所以不需要转换,自动转的val r2 : String = p.mapObj(2) {it"我的第三个元素是:$it"}println(r2)//我的第三个元素是:53454
}

5.运算符[]重载

class KtBase108 <INPUT> (vararg objects: INPUT, val isR: Boolean = true) {// 开启INPUT泛型的只读模式private val objectArray: Array<out INPUT> = objects// 运算符重载operator fun get(index: Int) : INPUT ? = objectArray[index].takeIf { isR }
}fun <INPUT> inputObj(item: INPUT) {// 小结:异步处理泛型接收,都用 String?,如果用String可能为空println((item as String?)?.length ?: "你个货传递的泛型数据是null啊")
}// TODO 108-Kotlin语言的[ ]操作符学习
// 1.给泛型传入null后,直接操作
fun main() {inputObj(null) //你个货传递的泛型数据是null啊println()// 只要有一个元素是null,那么所有的元素都是 String?val p1 : KtBase108<String?> = KtBase108("张三", "李四", "王五", null)var r : String? = p1[0]println(r) //张三println(p1[1]) //李四
}

6.协变out,逆变in

//特点:
//协变out T,作为返回值,只能被读取。相当于? extends T,out 父类 = 子类
//默认情况下,泛型的子类对象不可以赋值给泛型的父类对象,加上out可以
//例如List<CharSequence> list1 = new ArrayList<String>()会编译不过,需要List<? extends CharSequence> list2 = new ArrayList<String>();//逆变in T,作为参数,只能被修改。相当于? super T,in  子类 = 父类
//默认情况下,泛型的父类对象不可以赋值给泛型的子类对象,加上in可以
//例如List<String> list1 = new ArrayList<CharSequence>()会编译不过,需要List<? super String> list2 = new ArrayList<CharSequence>();// 生产者, 协变 out T 代表整个生产者类里面这个T只能被读取,不能被修改了
interface Producer<out T> {fun producer() : T// 不能被修改了 (编译不通过)// fun consumer(itme: T)  /*{  消费代码  }*/
}// 消费者 in T  逆变 [in T 此泛型只能被修改 更新 所以是in]
interface Consumer <in T> {
//    in T  代表整个生产者类里面  这个T  只能被读取,不能被修改了fun consumer(itme : T) /*{  消费代码  }*/// 不能被读取 (编译不通过)// fun producer() : T
}// 生产者&消费者 T  默认情况下,是不变
interface ProducerAndConsumer<T> {// 能被修改了fun consumer(itme : T) /*{  消费代码  }*/// 能被读取fun producer() : T
}open class Animal // 动物
open class Humanity : Animal() // 人类
open class Man : Humanity() // 男人
open class WoMan : Humanity() // 女人// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  只管生产者
class ProducerClass1 : Producer<Animal> {override fun producer(): Animal {println("生产者 Animal")return Animal()}
}class ProducerClass2 : Producer<Humanity> {override fun producer(): Humanity {println("生产者 Humanity")return Humanity()}
}class ProducerClass3 : Producer<Man> {override fun producer(): Man {println("生产者 Man")return Man()}
}// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  只管消费者
class ConsumerClass1 : Consumer<Animal> {override fun consumer(item: Animal) {println("消费者 Animal")}
}class ConsumerClass2 : Consumer<Humanity> {override fun consumer(item: Humanity) {println("消费者 Humanity")}
}fun main() {val p1 : Producer<Animal> = ProducerClass1() // ProducerClass1他本来就是 传递 Animal ,当然是可以的val p2 : Producer<Animal> = ProducerClass2() // ProducerClass2他本来就是 传递 Humanity,居然也可以,因为outval p3 : Producer<Animal> = ProducerClass3() // ProducerClass3他本来就是 传递 Man,居然也可以,因为outval p1 : Consumer<Man> = ConsumerClass1() // ConsumerClass1他本来就是 传递 Animal,居然也可以,因为inval p2 : Consumer<WoMan> = ConsumerClass2() // ConsumerClass1他本来就是 传递 Humanity,居然也可以,因为in
}

7.reified示例

// 1.定义3个Obj类
data class ObjectClass1(val name: String, val age: Int, val study: String)
data class ObjectClass2(val name: String, val age: Int, val study: String)
data class ObjectClass3(val name: String, val age: Int, val study: String)class KtBase112 {// 所有的功能,写在函数上// 默认随机输出一个对象,如果此对象和用户指定的对象不一致,我们就启用备用对象,否则就直接返回对象inline fun <reified T> randomOrDefault(defaultLambdaAction: () -> T ) :T? {val objList : List<Any> = listOf(ObjectClass1("obj1 李四", 22, "学习C"),ObjectClass2("obj2 王五", 23, "学习C++"),ObjectClass3("obj3 赵六", 24, "学习C#"))val randomObj : Any? = objList.shuffled().first()println("您随机产生的对象 幸运儿是:$randomObj")// return randomObj.takeIf { it is T } as T ?: null     :T? {// T  与  T?  是不同的// 答: it is T false  takeIf  null    null as T 奔溃了,解决思路: null as T?// 如果  it随机产生的对象 等于 T类型的,就会走 as T 直接返回了return randomObj.takeIf { it is T } as T?  // null as T     null as T?// 如果  it随机产生的对象 不等于 T类型的,就会走下面这个备用环节?: defaultLambdaAction()}
}// TODO 112-Kotlin语言的reified关键字学习
// 1.定义3个Obj类
// 2.randomOrDefault函数 备用机制的lambda
// 3.lists.shuffled()
fun main() {val finalResult = KtBase112().randomOrDefault<ObjectClass1> {println("由于随机产生的对象 和 我们指定的ObjectClass1不一致,所以启用备用对象")ObjectClass1("备用 obj1 李四", 22, "学习C") // 最后一行的返回}println("客户端最终结果:$finalResult")
}

17.扩展函数

//注意点:
// 第一点:如果我们自己写了两个一样的扩展函数,编译不通过
// 第二点:KT内置的扩展函数,被我们重复定义,属于覆盖,而且优先使用我们自己定义的扩展函数

class KtBase113 (val name: String, val age: Int, val sex: Char)// 增加扩展函数
fun KtBase113.show() {println("我是show函数, name:${name}, age:$age, sex:$sex")
}
fun KtBase113.getInfo() = "我是getInfo函数, name:${name}, age:$age, sex:$sex"
fun String.addExtAction(number: Int) =  this + "@".repeat(number) //this是String对象本身
fun <T> T.showContentInfo() = println("${if (this is String) "你的字符串长度是:$length" else "你不是字符串 你的内容是:$this"}")
fun <INPUTTYPE> INPUTTYPE.showTypesAction() =when(this) {is String -> "原来你是String类型"is Int -> "原来你是Int类型"is Char -> "原来你是Char类型"is Float -> "原来你是Float类型"is Double -> "原来你是Double类型"is Boolean -> "原来你是Boolean类型"is Unit -> "原来你是无参返回函数类型"else -> "未知类型"}// private 私有化
// inline  我们的函数是高阶函数,所以用到内联,做lambda的优化,性能提高
// fun<I, O> 在函数中,申明两个泛型,函数泛型  I输入Input, O输出Output
// I.mLet 对I输入Input进行函数扩展,扩展函数的名称是 mLet,意味着,所有的类型,万能类型,都可以用 xxx.mLet
// lambda : (I) -> O   (I输入参数) -> O输出
//  : O  会根据用户的返回类型,变化而变化
// lambda(this) I进行函数扩展,在整个扩展函数里面,this == I本身
private inline fun<I, O> I.mLet(lambda : (I) -> O) : O = lambda(this)// INPUT.() -> Unit 让我们的匿名函数里面持有 this ,在lambda里面不需要返回值,因为永远都是返回INPUT本身
// lambda(this) 默认就有this
// 返回this的目的是可以链式调用
private inline fun <INPUT> INPUT.mApply(lambda : INPUT.() -> Unit) : INPUT  {lambda() // 省略thisreturn this
}//函数也可以作为T泛型
fun commonFun() {}
fun commonFun2() = "DDD"// xxx.yyy()  函数里的this是xxx对象本身
// TODO 113-Kotlin语言的定义扩展函数学习
fun main() {val p = KtBase113("张三", 28, '男')p.show() //我是show函数, name:张三, age:28, sex:男println(p.getInfo()) //我是getInfo函数, name:张三, age:28, sex:男println("Kevin".addExtAction(3)) //Kevin@@@println(commonFun().showTypesAction()) //原来你是无参返回函数类型println(commonFun2().showTypesAction()) //原来你是String类型// 万能类型,任何类型,所有类型,都可以使用我的 mLetval r2 : String = "Derry2".let {it34543.45f'A'}val r : File = File("D:\\a.txt").mApply {// 输入的是 this == File对象本身setReadable(true)setWritable(true)println("1 ${readLines()}")}.mApply {// 输入的是 this == File对象本身setReadable(true)setWritable(true)println("2 ${readLines()}")}.mApply {// 输入的是 this == File对象本身setReadable(true)setWritable(true)println("3 ${readLines()}")}
}

18扩展属性

// val String.myInfo: String = "AAA",扩展属性不能直接复制,需要重写get方法
val String.myInfo: Stringget() = "Derry"

19.扩展文件及扩展函数重命名

KtBase120Ext.kt
// 1.扩展文件一般都是public,如果private外界无法使用
// 2.Iterable<E> 的子类 set list 都可以用,所以用父类
// 3.本次扩展函数的作用是,随机取第一个元素返回
fun <T> Iterable<T>.randomItemValuePrintln() = println(this.shuffled().first())// 导入扩展文件
// 在工作中非常有用,可以把很多的扩展操作,写到某一个地方,到时候引入过来用,比较独立化
import com.derry.s6.com.derry.randomItemValuePrintln
import com.derry.s6.com.derry.randomItemValuePrintln as p // as p 重命名扩展操作// TODO 120-Kotlin语言的定义扩展文件
fun main() {val list : List<String> = listOf("李元霸", "李连杰", "李小龙")val set : Set<Double> = setOf(545.5, 434.5, 656.6)// 使用 扩展文件list.randomItemValuePrintln()set.randomItemValuePrintln()list.p()set.p()
}

19.infix中缀函数

使用条件:用于成员方法或者扩展方法,且只有一个参数//用于扩展方法
val map = mapOf(1 to "one", 2 to "two", 3 to "three")infix fun Int.add(x: Int): Int {return this + x
}
println(100 add 200) //300private infix fun <C1, C2> C1.gogogo(c2: C2) {println("中缀表达式,C1是: $this, C2是: $c2")
}"Derry2" gogogo 'M' //中缀表达式,C1是: Derry2, C2是: M//用于成员方法
class Account {var balance = 100.0infix fun add(amount: Double) : Unit {this.balance = balance + amount}
}val  account = Account()
account add 100.00
print(account.balance) //200

Kotlin学习笔记相关推荐

  1. Kotlin 学习笔记(八)—— Kotlin类与对象之接口

    Kotlin 学习笔记(八)-- Kotlin类与对象之接口 Kotlin学习笔记系列教程 Kotlin 学习笔记(一)-- 概述.学习曲线.开发工具.参考资料 Kotlin 学习笔记(二)-- 基础 ...

  2. Kotlin学习笔记(3)- 语法

    系列文章全部为本人的学习笔记,若有任何不妥之处,随时欢迎拍砖指正.如果你觉得我的文章对你有用,欢迎关注我,我们一起学习进步!kotlin学习笔记系列首发简书和CSDN Kotlin学习笔记(1)- 环 ...

  3. Kotlin学习笔记(2)- 空安全

    系列文章全部为本人的学习笔记,若有任何不妥之处,随时欢迎拍砖指正.如果你觉得我的文章对你有用,欢迎关注我,我们一起学习进步!kotlin学习笔记系列首发简书和CSDN Kotlin学习笔记(1)- 环 ...

  4. Kotlin学习笔记(1)- 环境配置

    系列文章全部为本人的学习笔记,若有任何不妥之处,随时欢迎拍砖指正.如果你觉得我的文章对你有用,欢迎关注我,我们一起学习进步!kotlin学习笔记系列首发简书和CSDN Kotlin学习笔记(1)- 环 ...

  5. kotlin学习笔记——枚举、封闭类

    1.枚举 kotlin中提供类枚举的实现,与java相同.枚举可以带参数,如 enum Icon(val res: Int){MENU(R.drawable.menu),BACK(R.drawable ...

  6. kotlin学习笔记——重载操作符

    Kotlin中有很多操作符可以使用,具体可以见kotlin学习笔记--操作符_There is a Bug!!!-CSDN博客 Kotlin的一个特点就是可以重载这些操作符,为操作符赋予不同的行为. ...

  7. Kotlin 学习笔记(七)—— Kotlin类与对象之属性与字段

    Kotlin 学习笔记(七)-- Kotlin类与对象之属性与字段 Kotlin学习笔记系列教程 Kotlin 学习笔记(一)-- 概述.学习曲线.开发工具.参考资料 Kotlin 学习笔记(二)-- ...

  8. Kotlin学习笔记20 阶段复习2

    参考链接 示例来自bilibili Kotlin语言深入解析 张龙老师的视频 lambda表达式 内联函数 Kotlin学习笔记 第三章 函数 高阶函数 lambda表达式 内联函数_积跬步 至千里- ...

  9. Kotlin学习笔记19 阶段复习1

    参考链接 示例来自bilibili Kotlin语言深入解析 张龙老师的视频 基础部分 Kotlin学习笔记 第一章开始 第二章 基础_积跬步 至千里-CSDN博客 类与继承 Kotlin学习笔记 第 ...

  10. Kotlin学习笔记12——数据类和密封类

    Kotlin学习笔记12--数据类和密封类 前言 数据类 在类体中声明的属性 复制 componentN 解构声明 密封类 尾巴 前言 上一篇,我们学习了Kotlin中的拓展,今天继续来学习Kotli ...

最新文章

  1. 中兴通讯ZXR10 T40G交换机telnet配置
  2. linux slocate(secure locate) 命令详解
  3. 机器学习笔记:logistic regression
  4. Mac下配置svn服务器
  5. 子网/子网掩码原理简介
  6. 将pandas中Dataframe数据转换为二维数组array
  7. 互联网域名解析系统DNS的工作原理及相关服务配置
  8. BI软件应用在哪些方面
  9. cd4017引脚图及功能_芯片CD4017解析
  10. jenkins集成kettle
  11. tpac100控制器设置教程_tpac100控制器设置教程_TP-link AC控制器统一管理AP设置指导...
  12. openflow交换机 ryu_ryu—交换机
  13. 《股票大作手操盘术》读书笔记
  14. DTM、DEM、DSM与DOM的概念
  15. NW和Electron的区别
  16. 基于React和fabricjs开发的在线名片、海报设计器,大前端项目在线图片编辑器源码分享
  17. vue滑动窗口_vue-floating 浮窗组件、封装基于better-scroll的滑动组件、vue自定义手势指令...
  18. Python使用腾讯云-短信服务发送手机短信
  19. python语言表示语句结构_python基础语言以及if/while语句结构
  20. 期货交易怎么买空(期货怎么买做空)

热门文章

  1. OllyDbg的基本使用
  2. 网际层协议:IP协议
  3. Java 丢手绢游戏 求和_大班游戏活动_丢手绢
  4. 基于智能化环境下低压电力客户远程集中自动抄表系统的实现
  5. win10 tensorflow MTCNN Demo
  6. 揭秘清道夫轮巡码制作流程
  7. JavaFX官方文档
  8. devops数字化管理_可视化DevOps心态
  9. 苹果6s解除耳机模式_苹果耳机戴着耳朵痛
  10. java 关注公众号回调_处理公众号回调消息