1、Kotlin是静态语言还是动态语言?
答:是静态语言,在编译器判断;
图片.png
2、Kotlin类和Java区别:
Kotlin的函数可以写到类里面,也可以写到外面;
Java的方法只能写到类里面;
3、Kotlin编译时常量只能在函数之外定义,为什么?
编译时常量只能在函数之外定定义,就可以在编译期间初始化了(如果在函数之内定义,就必须在运行时才能调用函数赋值,何来编译时常量一说)
4、Kotlin语言只有一种数据类型
看起来都是引用类型,实际上编译器会在java字节码中,修改为"基本类型"
5、Kotlin函数类型隐式返回(也就是lambda函数)
//--------------第一种写法----------------
//第一步:函数输入输出的声明
val methodAction:() -> String
//第二步:对上面函数的实现
methodAction = {
"哈哈哈"//匿名函数不要写return,最后一行就是返回值
}
//第三步:调用此函数
println(methodAction())
//--------------第二种写法----------------
val methodAction :(Int,Int,Int) ->String ={number1,number2,number3 ->
"$number1,$number2,$number3,"
}
methodAction.invoke(1,2,3)
methodAction(1,2,3)
val methodAction2: (String) - >String = {"$it"}
//--------------第三种写法----------------
val methodAction3 ={number1,number2,number3 ->
"$number1,$number2,$number3,"
}
methodAction3(1,2,3)
//--------------代替接口返回写法----------------
fun login(name:String,pwd:String,result:(String,Int)->Unit){
result("登录成功",200)
}
//--------------第四种写法----------------
//方式一:
loginAPI("luo","123456"){ msg:String,code:Int ->
}
//方式二:
loginAPI("luo","123456",result = { msg:String,code:Int ->
})
//方式三:
loginAPI("luo","123456"){ msg:String,code:Int ->
}
//被调用的方法
fun loginAPI(name:String,pwd:String,result:(String,Int)->Unit){
result("登录成功",200)
}
6、内联函数
1、Kotlin函数使用lambda作为参数,就需要声明成内联;
2、lambda如果此函数,不使用内联。在调用端,会生成多个对象来完成lambda的调用(会造成性能损耗)->可以查看Kotlin编译的字节码;
3、如果此函数,使用内联,相当于C++ #define 宏定义 宏替换;会把代码替换到调用处,调用处没有任何函数的开辟,对象的开辟 的损耗;
总结:如果函数参数有lambda,尽量使用 inline 关键字,这样内部会做优化,减少函数开辟 对象开辟的性能损耗。
//内联函数
inline fun loginAPI(name:String,pwd:String,result:(String,Int)->Unit){
result("登录成功",200)
}
7、Kotlin 的函数引用学习
// TODO 32.Kotlin语言的函数引用学习
fun main() {
// 函数引用
// lambda属于函数类型的对象,需要把methodResponseResult普通函数变成 函数类型的对象(函数引用)
// login("Derry2", "123456", ::methodResponseResult)
val obj = ::methodResponseResult
val obj2 = obj
val obj3 = obj2
login("Derry", "123456", obj3)
}
fun methodResponseResult(msg: String, code: Int) {
println("最终登录的成果是:msg:$msg, code:$code")
}
// 模拟:数据库SQLServer
const val USER_NAME_SAVE_DB4 = "Derry"
const val USER_PWD_SAVE_DB4= "123456"
inline fun login(name: String, pwd: String, responseResult: (String, Int) -> Unit) {
if (USER_NAME_SAVE_DB4 == name && USER_PWD_SAVE_DB4 == pwd) {
// 登录成功
// 做很多的事情 校验成功信息等
responseResult("登录成功", 200)
// ...
} else {
// 登录失败
// 做很多的事情 登录失败的逻辑处理
// ...
responseResult("登录失败错了", 444)
}
}
8、Kotlin 返回一个函数
package com.derry.s2
// TODO 33.Kotlin语言的函数类型作为返回类型
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"
}
fun show3(info: String): String {
println("我是show函数 info:$info")
return /*888*/ ""
}
// showMethod函数 再返回一个 匿名函数
fun showMethod(info: String): (String, Int) -> String {
println("我是show函数 info:$info")
// return 一个函数 匿名函数
return { name: String, age: Int ->
"我就是匿名函数:我的name:$name, age:$age"
}
}
9、Kotlin语言的匿名函数与具名函数
Kotlin版:
// TODO 34.Kotlin语言的匿名函数与具名函数
fun main() {
// 匿名函数
showPersonInfo("lisi", 99, '男', "学习KT语言") {
println("显示结果:$it")
}
// 具名函数 showResultImpl
showPersonInfo("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版:
package com.derry.s2;
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() {
@Override
public void result(String result) {
System.out.println("显示结果:" + result);
}
});
// 具名函数 - 具名接口实现 showResultImpl
IShowResult showResultImpl = new MshowResultImpl();
showPersonInfo("wangwu", 88, 'n', "study kt", showResultImpl);
}
static class MshowResultImpl implements IShowResult {
@Override
public 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);
}
}
10、Kotlin 空合并操作符
//如果info等于null,打印 ?: 后面的值
var info = null
println(info?:"是null啊")
//let 函数+空合并操作符
println(info?.let{ $it}?:"是null啊")
11、kotlin 中==和===区别:
//== 值或者内容的比较,相当于java的equals
//=== 引用的比较
12、Kotlin语言中Double转Int与类型格式化:
fun main() {
println(65.4645654.toInt()) // 65 四舍五入
println(65.4645654.roundToInt()) // 65 四舍五入
println(65.8343433.roundToInt()) // 66 四舍五入
// 结论:用 roundToInt()函数,保证 Double ->转Int 持有四舍五入的效果
// r的类型: String,保留3位小数
val r = "%.3f".format(65.8343433)
println(r)
}
13、Kotlin语言的apply内置函数
示例: info.apply
1、apply函数返回类型,用于info本身;
2、apply函数的匿名函数里面持有的是this == info本身;
// info.apply特点:apply函数始终是返回 “info本身”,所以可以链式调用
var info = "xiaoming"
info?.apply {
println("长度是:$length")
}.apply {
println("最后一个字符是:${this[length -1]}")
true
}.apply {
println("全部转成小写是:${toLowerCase()}")
}
14、Kotlin语言的let内置函数
示例:value.let
1、let函数返回类型,是根据匿名函数最后一行的变化而变化;
2、let函数的匿名函数里面持有的是it == 集合本身;
// let方式 对集合第一个元素相加
val result2 = listOf(6, 5, 2, 3, 5, 7).let {
// it == list集合
it.first() + it.first()
}
println(result2)
// let方式 + 空合并操作符 对值判null,并返回 简化版本
fun getMethod4(value: String?) =
value?.let {
"欢迎回来${it}非常欢迎"
} ?: "你传递的内容是null,你在搞什么飞机"
15、Kotlin语言的run内置函数
str.run
1、run函数返回类型,是根据匿名函数最后一行的变化而变化;
2、run函数的 匿名函数里面持有的是this == str 本身;
fun main() {
val str = "Derry is OK"
val r1 : Float = str.run {
// this == str本身
true
5435.5f
}
println(r1)
// 下面是 具名函数 配合 run函数
// 2.具名函数判断长度 isLong
// 这个是属于 匿名函数 配合 run
str.run {
// this == str本身
}
// 这个是属于具名函数
// str.run(具名函数)
str
.run(::isLong) // this == str本身
.run(::showText) // this == isLong返回的boolean值
.run(::mapText)
.run(::println)
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 false
fun showText(isLong: Boolean) /*: String */ = if (isLong) "你的字符串合格" else "你的字符串不合格"
fun mapText(getShow: String) /*: String */ = "【$getShow】"
16、Kotlin语言的with内置函数
with(str) 和run 一样,只是调用方式不同
1、with函数返回类型,是根据匿名函数最后一行的变化而变化;
2、with函数的 匿名函数里面持有的是this == str 本身;
fun main() {
val str = "李元霸"
// 具名操作
/*with(str) {
this == str本身
}*/
val r1 = with(str, ::getStrLen)
val r2 = with(r1, ::getLenInfo)
val r3 = with(r2, ::getInfoMap)
with(r3, ::show)
println()
// 匿名操作
with(with(with(with(str) {
length
}) {
"你的字符串长度是:$this"
}){
"【$this】"
}){
println(this)
}
}
fun getStrLen(str: String) = str.length
fun getLenInfo(len: Int) = "你的字符串长度是:$len"
fun getInfoMap(info: String) = "【$info】"
fun show(content: String) = println(content)
17、Kotlin语言的also内置函数
示例: also.apply
1、also函数返回类型,用于str本身;
2、also函数的匿名函数里面持有的是this == str本身;
// 真正使用also函数的写法规则如下:
// str.also特点:also函数始终是返回 “str本身”,所以可以链式调用
str.also {
println("str的原始数据是:$it")
}.also {
println("str转换小写的效果是:${it.toLowerCase()}")
}.also {
println("结束了")
}
18、Kotlin语言的List创建与元素获取
小结:开发过程中,尽量使用 getOrElse 或 getOrNull,才能体现KT的亮点
// 普通取值方式: 索引
// 防止奔溃取值方式: getOrElse getOrNull
val list = listOf("Derry", "Zhangsan", "Lisi", "Wangwu")
// 我们写KT代码,一定不会再出现,空指针异常,下标越界异常
// 防止奔溃取值方式: getOrElse getOrNull
println(list.getOrElse(4402) {"你越界了啊"})
// getOrNull + 空合并操作符
println(list.getOrNull(222) ?: "你越界了哦哦")
19、Kotlin语言的可变List集合
// TODO 58.Kotlin语言的可变List集合学习
// 可变的集合
// 不可变集合 to 可变集合
// 可变集合 to 不可变集合
fun main() {
// 可变的集合
val list = mutableListOf("Derry", "Zhangsna", "Wangwu")
// 可变的集合,可以完成可变的操作
list.add("赵六")
list.remove("Wangwu")
println(list)
// 不可变集合 to 可变集合
val list2 = listOf(123, 456, 789)
// 不可以的集合,无法完成可变的操作
// list2.add
// list2.remove
val list3 : MutableList<Int> = list2.toMutableList()
// 可变的集合,可以完成可变的操作
list3.add(111)
list3.remove(123)
println(list3)
// 可变集合 to 不可变集合
val list4: MutableList<Char> = mutableListOf('A', 'B', 'C')
// 可变的集合,可以完成可变的操作
list4.add('Z')
list4.remove('A')
println(list4)
val list5: List<Char> = list4.toList()
// 不可以的集合,无法完成可变的操作
/*list5.add
list5.remove*/
}
20、Kotlin语言的mutator函数
// 1.mutator += -= 操作
// 2.removeIf
fun main() {
// 1.mutator += -= 操作
val list : MutableList<String> = mutableListOf("Derry", "DerryAll", "DerryStr", "Zhangsan")
list += "李四" // mutator的特性 += -+ 其实背后就是 运算符重载而已
list += "王五"
list -= "Derry"
println(list)
// 2.removeIf
// list.removeIf { true } // 如果是true 自动变量整个可变集合,进行一个元素一个元素的删除
list.removeIf { it.contains("Derr") } // 过滤所有的元素,只要是有 Derr 的元素,就是true 删除
println(list)
}
21、Kotlin语言的解构语法过滤元素学习
// 1.集合配合解构语法
// 2.反编译看Java给三个变量赋值的代码
// 3.解构屏蔽接收值
fun main() {
val list: List<String> = listOf("李元霸", "李小龙", "李连杰")
val(value1, value2, value3) = list
// value1 = "" val只读的
println("value1:$value1, value2:$value2, value3:$value3")
var(v1, v2, v3) = list
// v1 = "OK"
println("v1:$v1, v2:$v2, v3:$v3")
// 用_内部可以不接收赋值,可以节约一点性能
val(_ , n2, n3) = list
// println(_) _不是变量名,是用来过滤解构赋值的,不接收赋值给我
println("n2:$n2, n3:$n3")
}
22、Kotlin语言的Set创建与元素获取
// 1.set 定义 不允许重复
// 2.普通方式elementAt 会越界奔溃
// 3.elementAtOrElse elementAtOrNull
fun main() {
val set: Set<String> = setOf("lisi", "wangwu", "zhaoliu", "zhaoliu") // set集合不会出现重复元素的
println(set)
// set[0] 没有这样 [] 的功能 去Set集合元素
println(set.elementAt(0)) // [0]
println(set.elementAt(1))
println(set.elementAt(2))
// println(set.elementAt(3)) // [3] 奔溃 会越界
// println(set.elementAt(4)) // [4] 奔溃 会越界
println()
// 使用 list 或 set 集合,尽量使用 此方式,防止越界奔溃异常
println(set.elementAtOrElse(0) {"越界了"})
println(set.elementAtOrElse(100) {"越界了了"})
println(set.elementAtOrNull(0))
println(set.elementAtOrNull(111))
// OrNull + 空合并操作符 一起使用
println(set.elementAtOrNull(88) ?: "你越界啦啊")
}
//Kotlin语言的可变Set集合
fun main() {
val set : MutableSet<String> = mutableSetOf("李元霸", "李连杰")
set += "李俊"
set += "李天"
set -= "李连杰"
set.add("刘军")
set.remove("刘军")
println(set)
}
23、Kotlin语言的集合转换与快捷函数学习
// 1.定义可变list集合
// 2.List 转 Set 去重
// 3.List 转 Set 转 List 也能去重
// 4.快捷函数去重 distinct
fun main() {
val list : MutableList<String> = mutableListOf("Derry", "Derry", "Derry", "Leo", "Lance") // list 可以重复元素
println(list)
// List 转 Set 去重
val set /*: Set<String>*/ = list.toSet()
println(set)
// List 转 Set 转 List 也能去重
val list2 /*: List<String>*/ = list.toSet().toList()
println(list2)
// 快捷函数去重 distinct
println(list.distinct()) // 内部做了:先转变成 可变的Set结合 在转换成 List集合
println(list.toMutableSet().toList()) // 和上面代码等价
}
24、Kotlin语言的Map的创建
fun main() {
val mMap1 : Map<String, Double> = mapOf<String, Double>("Derry" to(534.4), "Kevin" to 454.5)
val mMap2 = mapOf(Pair("Derry", 545.4), Pair("Kevin", 664.4))
// 上面两种方式是等价的哦
}
25、Kotlin语言的读取Map的值
// 方式一 [] 找不到会返回null
// 方式二 getOrDefault
// 方式三 getOrElse
// 方式四 与Java一样 会奔溃
fun main() {
val mMap /*: Map<String, Int>*/ = mapOf("Derry" to 123,"Kevin" to 654)
// 方式一 [] 找不到会返回null
println(mMap["Derry"]) // 背后对[] 运算符重载了
println(mMap["Kevin"])
println(mMap.get("Kevin")) // get 与 [] 完完全全等价的
println(mMap["XXX"]) // map通过key找 如果找不到返回null,不会奔溃
println()
// 方式二 getOrDefault
println(mMap.getOrDefault("Derry", -1))
println(mMap.getOrDefault("Derry2", -1))
// 方式三 getOrElse
println(mMap.getOrElse("Derry") {-1})
println(mMap.getOrElse("Derry2") {-1})
println()
// 方式四 getValue 与Java一样 会奔溃 尽量不要使用此方式
println(mMap.getValue("Derry"))
println(mMap.getValue("XXX"))
// map获取内容,尽量使用 方式二 方式三
}
26、Kotlin语言的遍历Map学习
// 四种方式遍历
fun main() {
val map /*: Map<String, Int>*/ = mapOf(Pair("Derry", 123), Pair("Kevin", 456), "Leo" to 789)
// 第一种方式:
map.forEach {
// it 内容 每一个元素 (K 和 V) 每一个元素 (K 和 V) 每一个元素 (K 和 V)
// it 类型 Map.Entry<String, Int>
println("K:${it.key} V:${it.value}")
}
println()
// 第二种方式:
map.forEach { key: String, value: Int ->
// 把默认的it给覆盖了
println("key:$key, value:$value")
}
println()
// 第三种方式:
map.forEach { (k /*: String*/, v /*: Int*/) ->
println("key:$k, value:$v")
}
println()
// 第四种方式:
for (item /*: Map.Entry<String, Int>*/ in map) {
// item 内容 每一个元素 (K 和 V) 每一个元素 (K 和 V) 每一个元素 (K 和 V)
println("key:${item.key} value:${item.value}")
}
}
27、Kotlin语言的可变Map集合学习
// 1.可变集合的操作 += [] put
// 2.getOrPut 没有的情况
// 3.getOrPut 有的情况
fun main() {
// 1.可变集合的操作 += [] put
val map : MutableMap<String, Int> = mutableMapOf(Pair("Derry", 123), "Kevin" to 456, Pair("Dee", 789))
// 下面是可变操作
map += "AAA" to(111)
map += "BBB" to 1234
map -= "Kevin"
map["CCC"] = 888
map.put("DDD", 999) // put 和 [] 等价的
// 2.getOrPut 没有有的情况
// 如果整个map集合里面没有 FFF的key 元素,我就帮你先添加到map集合中去,然后再从map集合中获取
val r: Int = map.getOrPut("FFF") { 555 }
println(r)
println(map["FFF"]) // 他已经帮你加入进去了,所以你可以获取
// 3.getOrPut 有的情况
val r2 = map.getOrPut("Derry") {666} // 发现Derry的key是有的,那么就直接获取出来, 相当于666备用值就失效了
println(r2)
}
28、 主构造函数
// 主构造函数:规范来说,都是增加_xxx的方式,临时的输入类型,不能直接用,需要接收下来 成为变量才能用
// _name 等等,都是临时的类型,不能直接要弄,需要转化一下才能用
class KtBase72(_name: String, _sex: Char, _age: Int, _info: String) // 主构造函数
{
var name = _name
get() = field // get不允许私有化
private set(value) {
field = value
}
val sex = _sex
get() = field
// set(value) {} 只读的,不能修改的,不能set函数定义
val age: Int = _age
get() = field + 1
val info = _info
get() = "【${field}】"
fun show() {
// println(_name) 临时的输入类型,不能直接用,需要接收下来 成为变量才能用
println(name)
println(sex)
println(age)
println(info)
}
}
// TODO 72.Kotlin语言的主构造函数学习
fun main() {
// KtBase72()
val p = KtBase72(_name = "Zhangsan", _info = "学习KT语言", _age = 88, _sex = 'M')
// println(p.name)
// p.name = "AAA" 被私有化了,不能调用
p.show()
}
/* 伪代码:
class KtBase73 (_name: String, _sex: Char, _age: Int, _info: String)
{
var name = _name
val sex = _sex
val age = _age
var info = _info
fun show() {
println(name)
}
}
*/
// var name: String 就相当于 var name = _name 这不过你看不到而已
// 一步到位,不像我们上一篇是分开写的
class KtBase73 (var name: String, val sex: Char, val age: Int, var info: String)
{
fun show() {
println(name)
println(sex)
println(age)
println(info)
}
}
// TODO 73.Kotlin语言的主构造函数里定义属性
fun main() {
KtBase73(name = "Zhangsan", info = "学习KT语言", age = 88, sex = 'M').show()
}
29、次构造函数
class KtBase74(name: String) // 主构造
{
// 2个参数的次构造函数,必须要调用主构造函数,否则不通过, 为什么次构造必须调用主构造?答:主构造统一管理 为了更好的初始化设计
constructor(name: String, sex: Char) : this(name) {
println("2个参数的次构造函数 name:$name, sex:$sex")
}
// 3个参数的次构造函数,必须要调用主构造函数
constructor(name: String, sex: Char, age: Int) : this(name) {
println("3个参数的次构造函数 name:$name, sex:$sex, age:$age")
}
// 4个参数的次构造函数,必须要调用主构造函数
constructor(name: String, sex: Char, age: Int, info: String) : this(name) {
println("4个参数的次构造函数 name:$name, sex:$sex, age:$age, info:$info")
}
}
// TODO 74.Kotlin语言的次构造函数学习
// name: String, sex: Char, age: Int, info: String
fun main() {
val p = KtBase74("李元霸") // 调用主构造
KtBase74("张三", '男') // 调用 2个参数的次构造函数
KtBase74("张三2", '男', 88) // 调用 3个参数的次构造函数
KtBase74("张三3", '男', 78, "还在学校新语言") // 调用 4个参数的次构造函数
}
30、构造函数的默认值
class KtBase75(name: String = "李元霸") // 主构造
{
// 2个参数的次构造函数,必须要调用主构造函数
constructor(name: String = "李连杰", sex: Char = 'M') : this(name) {
println("2个参数的次构造函数 name:$name, sex:$sex")
}
// 3个参数的次构造函数,必须要调用主构造函数
constructor(name: String = "李小龙", sex: Char = 'M', age: Int = 33) : this(name) {
println("3个参数的次构造函数 name:$name, sex:$sex, age:$age")
}
// 4个参数的次构造函数,必须要调用主构造函数
constructor(name: String = "李俊", sex: Char = 'W', age: Int = 87, info: String = "还在学校新开发语言") : this(name) {
println("4个参数的次构造函数 name:$name, sex:$sex, age:$age, info:$info")
}
}
// TODO 75.Kotlin语言的构造函数中默认参数学习
fun main() {
val p = KtBase75("李元霸2") // 调用主构造
KtBase75("张三", '男') // 调用 2个参数的次构造函数
KtBase75("张三2", '男', 88) // 调用 3个参数的次构造函数
KtBase75("张三3", '男', 78, "还在学校新语言") // 调用 4个参数的次构造函数
KtBase75() // 到底是调用哪一个 构造函数,是次构造 还是 主构造 ? 答:优先调用主构造函数
}
31、lateinit 懒加载
lateinit 是在使用的时候,手动加载的懒加载方式,然后再使用
惰性初始化by lazy 是在使用的时候,自动加载的懒加载方式,然后再使用
class KtBase78 {
// lateinit val AAA; // AAA 无法后面在修改了,我还怎么延时初始化?
lateinit var responseResultInfo: String // 我等会儿再来初始化你,我先定义再说,所以没有赋值
// 模拟服务器加载
fun loadRequest() { // 延时初始化,属于懒加载,用到你在给你加载
responseResultInfo = "服务器加载成功,恭喜你"
}
fun showResponseResult() {
// 由于你没有给他初始化,所以只有用到它,就奔溃
// if (responseResultInfo == null) println()
// println("responseResultInfo:$responseResultInfo")
if (::responseResultInfo.isInitialized) {
println("responseResultInfo:$responseResultInfo")
} else {
println("你都没有初始化加载,你是不是忘记加载了")
}
}
}
// TODO 78.Kotlin语言的延迟初始化lateinit学习
// 1.lateinit responseResultInfo 定义
// 2.request 懒加载
// 3.showResponseResult
// 4.main 先请求 在显示
fun main() {
val p = KtBase78()
// 使用他之前,加载一下(用到它才加载,就属于,懒加载)
p.loadRequest()
// 使用他
p.showResponseResult()
}
32、Kotlin语言的继承与重载的open关键字学习
// KT所有的类,默认是final修饰的,不能被继承,和Java相反
// open:移除final修饰
open class Person(private val name: String) {
private fun showName() = "父类 的姓名是【$name】"
// KT所有的函数,默认是final修饰的,不能被重写,和Java相反
open fun myPrintln() = println(showName())
}
class Student(private val subName: String) : Person(subName) {
private fun showName() = "子类 的姓名是【${subName}】"
override fun myPrintln() = println(showName())
}
// TODO 83.Kotlin语言的继承与重载的open关键字学习
// 1.父类 val name showName()->String myPrintln->Unit
// 2.子类 myPrintln->Unit
fun main() {
val person: Person = Student("张三")
person.myPrintln()
}
33、Kotlin语言的对象声明学习
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)
println(KtBase87) // 背后代码:println(KtBase87.INSTANCE)
println(KtBase87)
println(KtBase87)
println(KtBase87)
println(KtBase87)
// 背后代码:KtBase87.INSTANCE.show();
println(KtBase87.show())
}
34、Kotlin语言的对象表达式学习
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")
}
// TODO 88.Kotlin语言的对象表达式学习
// 1.add del println
// 2.匿名对象表达式方式
// 3.具名实现方式
// 4.对Java的接口 用对象表达式方式
fun main() {
// 匿名对象 表达式方式
val p : KtBase88 = 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("李连杰")
// 具名实现方式
val p2 = KtBase88Impl()
p2.add("刘一")
p2.del("刘二")
// 对Java的接口 用 KT[对象表达式方式] 方式一
val p3 = object : Runnable {
override fun run() {
println("Runnable run ...")
}
}
p3.run()
// 对Java的接口 用 Java最简洁的方式 方式二
val p4 = Runnable {
println("Runnable run2 ...")
}
p4.run()
// 对KT的接口 用 KT[对象表达式方式] 方式一
object : RunnableKT {
override fun run() {
println("RunnableKT 方式一 run ...")
}
}.run()
// 对KT的接口 用 Java最简洁的方式 方式二
/*RunnableKT {
}*/
}
// 小结:Java接口,有两种方式 1(object : 对象表达式) 2简洁版,
// KT接口,只有一种方式 1(object : 对象表达式)
// 具名实现 具体名字 == KtBase88Impl
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")
}
}
35、Kotlin语言的伴生对象学习
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 {
@NotNull
public final String getInfo() {
return KtBase89.info;
}
@NotNull
public 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 method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
*/
}
// TODO 89.Kotlin语言的伴生对象学习
// 伴生对象的由来: 在KT中是没有Java的这种static静态,伴生很大程度上和Java的这种static静态 差不多的
// 无论 KtBase89() 构建对象多少次,我们的伴生对象,只有一次加载
// 无论 KtBase89.showInfo() 调用多少次,我们的伴生对象,只有一次加载
// 伴生对象只会初始化一次
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()
// new KtBase89();
KtBase89()
KtBase89()
KtBase89()
KtBase89()
// ...
}
36、Kotlin语言的嵌套类学习
// TODO 内部类
// 内部类的特点: 内部的类 能访问 外部的类
// 外部的类 能访问 内部的类
class Body(_bodyInfo: String) { // 身体类
val bodyInfo = _bodyInfo
fun show() {
Heart().run()
}
// 默认情况下:内部的类 不能访问 外部的类,要增加修饰符inner 成为内部类才可以访问外部类
inner class Heart { // 心脏类
fun run() = println("心脏访问身体信息:$bodyInfo")
}
inner class Kidney { // 肾脏
fun work() = println("肾脏访问身体信息:$bodyInfo")
}
inner class Hand { // 手
inner class LeftHand { // 左手
fun run() = println("左手访问身体信息:$bodyInfo")
}
inner class RightHand { // 右手
fun run() = println("右手访问身体信息:$bodyInfo")
}
}
}
// TODO 嵌套类
// 默认情况下:就是嵌套类关系
// 嵌套类特点:外部的类 能访问 内部的嵌套类
// 内部的类 不能访问 外部类的成员
class Outer {
val info: String = "OK"
fun show() {
Nested().output()
}
class Nested {
fun output() = println("嵌套类")
}
}
// TODO 90.Kotlin语言的嵌套类学习
fun main() {
// 内部类:
Body("isOK").Heart().run()
Body("isOK").Hand().LeftHand().run()
Body("isOK").Hand().RightHand().run()
// 嵌套类:
Outer.Nested().output()
}
37、.Kotlin语言的数据类学习
数据类使用条件:
条件一:服务器请求回来的响应的 JavaBean LoginResponseBean 基本上可以使用 数据类
条件二:数据类至少必须有一个参数的主构造函数
条件三:数据类必须有参数, var val 的参数
条件四:数据类不能使用 abstract,open,sealed,inner 等等 修饰 (数据类,数据载入的事情 数据存储)
条件五:需求 比较,copy,toString,解构,等等 这些丰富的功能时,也可以使用数据类
// 普通类
class ResponseResultBean1(var msg: String, var code: Int, var data: String) : Any()
// set get 构造函数
// 数据类 -- 一般是用于 JavaBean的形式下,用数据类
data class ResponseResultBean2(var msg: String, var code: Int, var data: String) : Any()
// set get 构造函数 解构操作 copy toString hashCode equals 数据类 生成 更丰富
// TODO 91.Kotlin语言的数据类学习
// 1.普通类 与 数据类 的 toString 背后原理
// 2.前面学习过的 == 与 ===
// 3.普通类的 == 背后原理
// 4.数据类的 == 背后原理
fun main() {
// val (v1, v2, v3) =list 这个是list集合之前的 解构操作
println(ResponseResultBean1("loginSuccess", 200, "登录成功的数据..."))
// 普通类:: Any() toString Windows实现打印了 com.derry.s5.ResponseResultBean1@266474c2
println(ResponseResultBean2("loginSuccess", 200, "登录成功的数据..."))
// 数据类:: Any() 默认重写了 父类的 toString 打印子类的toString详情 ResponseResultBean2(msg=loginSuccess, code=200, data=登录成功的数据...)
println()
// =====================
// 前面我们学习 == 值的比较 相当于java的equals ===引用 对象 比较
println( // 推理 两个 普通类 的值 是一样的,应该是true ,实际背后并不是这样的
ResponseResultBean1("loginSuccess", 200, "登录成功的数据...") ==
ResponseResultBean1("loginSuccess", 200, "登录成功的数据...")
)
// Any父类的 equals 实现 (ResponseResultBean1对象引用 比较 ResponseResultBean1对象引用)
println(
ResponseResultBean2("loginSuccess", 200, "登录成功的数据...") ==
ResponseResultBean2("loginSuccess", 200, "登录成功的数据...")
)
// Any父类的 equals 被 数据类 重写了 equals 会调用 子类的 equals函数(对值的比较)
}
38、Kotlin语言的copy函数学习
注意事项:使用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 + ")";
}
*/
// TODO 92.Kotlin语言的copy函数学习
fun main() {
val p1 = KtBase92("李元霸") // 调用次构造初始化对象
println(p1)
val newP2 = p1.copy("李连杰", 78)
println(newP2)
// copy toString hashCode equals 等等... 主管主构造,不管次构造
// 注意事项:使用copy的时候,由于内部代码只处理主构造,所以必须考虑次构造的内容
}
39、Kotlin语言的解构声明学习
// 普通类
class Student1(var name: String , var age: Int, var sex: Char) {
// 注意事项:component0 顺序必须是 component1 component2 component3 和成员一一对应,顺序下来的
operator fun component1() = name
operator fun component2() = age
operator fun component3() = sex
}
// 数据类
data class Student2Data(var name: String , var age: Int, var sex: Char)
// TODO 93.Kotlin语言的解构声明学习
fun main() {
val(name, age, sex) = Student1("李四", 89, '男')
println("普通类 结构后:name:$name, age:$age, sex:$sex")
val(name1, age1, sex1) = Student2Data("李四", 89, '男')
println("数据类 结构后:name:$name1, age:$age1, sex:$sex1")
val(_, age2, _) = Student1("李四", 89, '男')
println("数据类 结构后: age2:$age2")
}
40、Kotlin语言的枚举类学习
// KT想表达:枚举其实也是一个class,为什么,就是为了 枚举可以有更丰富的功能
enum class Week {
星期一,
星期二,
星期三,
星期四,
星期五,
星期六,
星期日
}
// TODO 95-Kotlin语言的枚举类学习
fun main() {
println(Week.星期一)
println(Week.星期四)
// 枚举的值 等价于 枚举本身
println(Week.星期二 is Week)
}
41、Kotlin语言的枚举类定义函数学习
package com.derry.s5
// 四肢信息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)) // 右脚
; // 结束枚举值
// 1. WEEK 这个时候 再定义单调的 枚举值,就报错了,必须所有枚举值,保持一致的效果
// 2. 枚举的 主构造的参数 必须和 枚举(的参数) 保持一致
fun show() = "四肢是:${limbsInfo.limbsInfo}的长度是:${limbsInfo.length}"
fun updateData(limbsInfo: LimbsInfo) {
println("更新前的数据是:${this.limbsInfo}")
this.limbsInfo.limbsInfo = limbsInfo.limbsInfo
this.limbsInfo.length = limbsInfo.length
println("更新后的数据是:${this.limbsInfo}")
}
}
// TODO 96-Kotlin语言的枚举类定义函数学习
fun main() {
// 显示枚举值
// 一般不会这样用
/*println(Limbs.show())
println(Limbs().show())*/
// 一般的用法如下:
println(Limbs.LEFT_HAND.show())
println(Limbs.RIGHT_HAND.show())
println(Limbs.LEFT_FOOT.show())
println(Limbs.RIGHT_FOOT.show())
println()
// 更新枚举值
Limbs.RIGHT_HAND.updateData(LimbsInfo("右手2", 99))
Limbs.LEFT_HAND.updateData(LimbsInfo("左手2", 99))
Limbs.LEFT_FOOT.updateData(LimbsInfo("左脚2", 199))
Limbs.RIGHT_FOOT.updateData(LimbsInfo("右叫2", 199))
}
42、Kotlin语言的代数数据类型
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 97-Kotlin语言的代数数据类型
// 1.定义枚举Exam类,四个级别分数情况
// 2.定义Teacher老师类,when使用枚举类
// 3.需求 得到优秀的孩子姓名
fun main() {
println(Teacher(Exam.Fraction1).show())
println(Teacher(Exam.Fraction3).show())
}
43、Kotlin语言的密封类学习
// 密封类,我们成员, 就必须有类型 并且 继承本类
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.Fraction2).show())
println(Teachers(Exams.Fraction3).show())
println(Teachers(Exams.Fraction4("李四")).show()) // 对象1
println(Teachers(Exams.Fraction4("王五")).show()) // 对象2
println(Exams.Fraction1 === Exams.Fraction1) // true, === 必须对象引用, object是单例 只会实例化一次
println(Exams.Fraction4("AAA") === Exams.Fraction4("AAA")) // class 有两个不同的对象,所以是false
}
44、Kotlin语言的接口定义
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() = field
set(value) {
field = value
}
override var usbInsertDevice: String = "键盘接入了UBS口"
get() {
println("@你get了[${field}]值出去了")
return field
}
set(value) {
field = value
println("@你set了[${value}]值进来了")
}
override fun insertUBS(): String = "KeyBoard $usbVersionInfo, $usbInsertDevice"
}
// 1.接口里面的所有成员 和 接口本身 都是 public open 的,所以不需要open,这个是接口的特殊
// 2.接口不能有主构造,反正就是没有构造
// 3.实现类不仅仅要重写接口的函数,也要重写 接口的成员
// 4.接口实现代码区域,全部都要增加 override 关键字来修饰
fun main() {
val iusb1 : IUSB = Mouse()
println(iusb1.insertUBS())
println()
val iusb2: IUSB = KeyBoard()
println(iusb2.insertUBS())
iusb2.usbInsertDevice = "AAA"
}
45、Kotlin 每个字段都有set和get方法
interface USB2 {
// 1.接口 var 也是不能给接口的成员赋值的 (但是有其他办法)
// 2.任何类 接口 等等 val 代表只读的,是不可以在后面动态赋值 (也有其他办法)
val usbVersionInfo: String // USB版本相关的信息
get() = (1..100).shuffled().last().toString()
// val 不需要set
val usbInsertDevice: String // USB插入的设备信息
get() = "高级设备接入USB"
// val 不需要set
fun insertUBS() : String
}
46、Kotlin语言的定义泛型类
class KtBase103<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)
// TODO 103-Kotlin语言的定义泛型类
// 1.定义 对象输出器 println(obj)
// 2.定义两个对象,三个属性
// 3.对象 String Int Double Float Char 等 测试 对象输出器
fun main() {
val stu1 = Student("张三", 88, '男')
val stu2 = Student("李四", 78, '女')
val tea1 = Teacher("王五", 77, '男')
val tea2 = Teacher("赵六", 89, '女')
KtBase103(stu1).show()
KtBase103(stu2).show()
KtBase103(tea1).show()
KtBase103(tea2).show()
KtBase103(String("刘一".toByteArray())).show()
KtBase103(575).show()
KtBase103(53456.45).show()
KtBase103(4645.5f).show()
KtBase103('男').show()
}
47、Kotlin语言的泛型变换实战
// 1.类 isMap map takeIf map是什么类型
class KtBase105<T>(val isMap: Boolean = false, val inputType: T) {
// 模仿RxJava T是要变化的输入类型 R是变换后的输出类型
// 要去map返回的类型是 R? == 有可能是R 有可能是null
inline 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
it.toString() // lambda最后一行是 返回值
"我的it是:$it" // lambda最后一行是 返回值
}
// 4.验证是否是此类型 与 null
val str1: String = "OK1"
val str2: String? = "OK2"
println(r is String)
println(r is String?)
println(r ?: "大哥你是null,你在搞什么飞机...,你是不是传入了isMap是false")
println()
// 3.map per -> stu 最终接收是什么类型
val p2 = KtBase105(true, Persons("李四", 99))
val r2 : Students? = p2.map {
// it == Persons对象 == inputType
it
Students(it.name, it.age)
}
println(r2)
println()
// map函数 模仿RxJava变换操作
val r3 = map(123) {
it.toString()
"map包裹[$it]" // lambda表达式最后一行,就是返回值
}
println(r3)
123.run { }
}
data class Persons(val name: String, val age: Int)
data class Students(val name: String, val age: Int)
48、Kotlin语言的out-协变学习
package com.derry.s6
// 生产者 out T 协变 [out T 此泛型能够被获取 读取 所以是out]
interface Producer<out T> {
// out T 代表整个生产者类里面 这个T 只能被读取,不能被修改了
// 不能被修改了 (编译不通过)
// fun consumer(itme: T) /*{ 消费代码 }*/
// 只能被读取
fun producer() : T
}
// 消费者 in T 逆变 [in T 此泛型只能被修改 更新 所以是in]
interface Consumer <in T> {
// out 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 ProducerClass4 : Producer<WoMan> {
override fun producer(): WoMan {
println("生产者 WoMan")
return WoMan()
}
}
// TODO 109-Kotlin语言的out-协变学习
// 1.Producer Consumer 不变
// 2.ProducerClass4
// 3.main 测试
fun main() {
val p1 : Producer<Animal> = ProducerClass1() // ProducerClass1他本来就是 传递 Animal ,当然是可以的
val p2 : Producer<Animal> = ProducerClass2() // ProducerClass2他本来就是 传递 Humanity,居然也可以,因为out
val p3 : Producer<Animal> = ProducerClass3() // ProducerClass3他本来就是 传递 Man,居然也可以,因为out
val p4 : Producer<Animal> = ProducerClass4() // ProducerClass4他本来就是 传递 WoMan,居然也可以,因为out
// 泛型默认情况下是:泛型的子类对象 不可以赋值给 泛型的父类对象
// 泛型默认情况下是:泛型具体处的子类对象 不可以赋值给 泛型声明处的父类对象
// out: 泛型的子类对象 可以赋值给 泛型的父类对象
// out: 泛型具体出的子类对象 可以赋值给 泛型声明处的父类对象
// 协变:父类 泛型声明处 可以接收 子类 泛型具体处
}
49、Kotlin语言的in-逆变学习
package com.derry.s6
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 只管消费者
class ConsumerClass1 : Consumer<Animal> {
override fun consumer(item: Animal) {
println("消费者 Animal")
}
}
class ConsumerClass2 : Consumer<Humanity> {
override fun consumer(item: Humanity) {
println("消费者 Humanity")
}
}
class ConsumerClass3 : Consumer<Man> {
override fun consumer(item: Man) {
println("消费者 Man")
}
}
class ConsumerrClass4 : Consumer<WoMan> {
override fun consumer(item: WoMan) {
println("消费者 WoMan")
}
}
// TODO 110-Kotlin语言的in-逆变学习
fun main() {
val p1 : Consumer<Man> = ConsumerClass1() // ConsumerClass1他本来就是 传递 Animal,居然也可以,因为in
val p2 : Consumer<WoMan> = ConsumerClass2() // ConsumerClass1他本来就是 传递 Humanity,居然也可以,因为in
// 默认情况下: 泛型具体出的父类 是不可以赋值给 泛型声明处的子类的
// in:泛型具体出的父类 是可以赋值给 泛型声明处的子类的
// 逆变:子类 泛型声明处 可以接收 父类 泛型具体处
// 协变:out 父类 = 子类
// 逆变:in 子类 = 父类
}
50、Kotlin语言中使用in和out
package com.derry.s6
// in T out T 声明处指定关系 声明处泛型 这个是Java没有的功能
// 整个 SetClass 里面的所有成员 泛型相关,只能修改 更改,
// 不能获取人家 读取人家的
// 小结:当我们 对这个整个类里面的泛型,只能修改 ,不能让外界读取时,可以声明 in T 逆变
class SetClass<in T>() {
// 200个函数 这200个函数 对T只能修改,不能给外界读取
// ...
fun set1(item: T) {
println("set1 你要设置的item是:$item")
}
fun set2(item: T) {
println("set2 你要设置的item是:$item")
}
fun set3(item: T) {
println("set3 你要设置的item是:$item")
}
// ...
// 不能给外界读取 (增加in后,不能给外界读取,所以编译不通过)
/*fun get1() : T? {
return null
}
fun get2() : T? {
return null
}
fun get3() : T? {
return null
}*/
// ...
}
// 整个 GetClass 里面的所有成员 泛型相关,不能修改 更改,
// 只能获取人家 读取人家的
// 小结:当我们 对这个整个类里面的泛型,只能给读取 ,不能修改 更改,可以声明 out T 协变
class GetClass<out T>(_item: T) {
val item: T = _item
// 200个函数 这200个函数 对T只能读取,不能给外界修改 更改
// ...
// 不能给外界修改 更改 (增加out后,不能给外界修改 更改,所以编译不通过)
/*fun set1(item : T) {
println("set1 你要设置的item是:$item")
}
fun set2(item : T) {
println("set2 你要设置的item是:$item")
}
fun set3(item : T) {
println("set3 你要设置的item是:$item")
}*/
// ...
fun get1(): T {
return item
}
fun get2(): T {
return item
}
fun get3(): T? {
return item
}
// ...
}
// TODO 111-Kotlin语言中使用in和out
fun main() {
// 逆变 in T SetClass 只能修改 更改 不能给外界读取
val p1 = SetClass<String>()
p1.set1("Derry")
p1.set2("Kevin")
println()
// 协变 out T GetClass 只能读取,不能修改 更改
val p2 = GetClass("李四")
println(p2.get1())
val p3 = GetClass("王五")
println(p3.get3())
}
51、Kotlin语言的reified关键字学习
package com.derry.s6
// 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")
}
52、Kotlin语言的泛型扩展函数
package com.derry.s6
// 1.String类型就输出长度
fun <T> T.showContentInfo() = println("${if (this is String) "你的字符串长度是:$length" else "你不是字符串 你的内容是:$this"}")
// 2.显示调用时间
fun <I> I.showTime() = println("你当前调用的时间是:${System.currentTimeMillis()}, 内容是:$this")
// 3.显示调用者的类型
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 -> "未知类型"
}
fun commonFun() {}
// fun commonFun2() = "DDD" 这个不管他
// TODO 115-Kotlin语言的泛型扩展函数
// 1.String类型就输出长度
// 2.显示调用时间
// 3.显示调用者的类型
fun main() {
345.showContentInfo()
'C'.showContentInfo()
false.showContentInfo()
345.45f.showContentInfo()
53454.45.showContentInfo()
"Derry".showContentInfo()
commonFun().showContentInfo()
// commonFun2().showContentInfo()
// 太多了,不写了 .... 省略
// 所有类型 都是泛型,你对泛型扩展了showContentInfo,那么所有类型都可以使用showContentInfo
println()
345.showTime()
'C'.showTime()
false.showTime()
345.45f.showTime()
53454.45.showTime()
"Derry".showTime()
commonFun().showTime()
// commonFun2().showTime()
// 太多了,不写了 .... 省略
println()
println(345.showTypesAction())
println('C'.showTypesAction())
println(false.showTypesAction())
println(345.45f.showTypesAction())
println(53454.45.showTypesAction())
println("Derry".showTypesAction())
println(commonFun().showTypesAction())
// println(commonFun2().showTypesAction())
}
53、Kotlin语言的标准函数与泛型扩展函数
package com.derry.s6
// TODO 116-Kotlin语言的标准函数与泛型扩展函数
fun main() {
val r: Char = "Derry".mLet {
it
true
"OK"
'A'
}
123.mLet {
it
}
'C'.mLet {
it
}
// 万能类型,任何类型,所有类型,都可以使用我的 mLet
// 省略几万行代码 ...
val r2 : String = "Derry2".let {
it
34543.45f
"Derry"
}
}
// 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)
54、Kotlin语言的扩展属性
package com.derry.s6
// 你必须把前面的普通方式学会:
val myStr : String = "AAA"
/* 背后代码:
public final class KtBase117Kt {
@NotNull
private static final String myStr = "AAA";
@NotNull
public static final String getMyStr() {
return myStr;
}
}
*/
// 扩展属性:
val String.myInfo: String
get() = "Derry"
/* 背后代码:
public final class KtBase117Kt {
真实情况:
@NotNull
public static final String getMyInfo(@NotNull String $this$myInfo) {
Intrinsics.checkParameterIsNotNull($this$myInfo, "$this$myInfo");
return "Derry";
}
}
*/
// 打印输出 并且 链式调用 (只有String有资格这样)
fun String.showPrintln() : String {
println("打印输出 并且 链式调用 (只有String有资格这样):内容$this")
return this
}
val String.stringAllInfoValueVal
get() = "当前${System.currentTimeMillis()}这个时间点被调用了一次,当前的值是:$this,当前字符串长度是:$length"
// TODO 117-Kotlin语言的扩展属性
fun main() {
val str : String = "ABC"
println(str.myInfo)
str.showPrintln().showPrintln().showPrintln().showPrintln()
str.myInfo.showPrintln().showPrintln().showPrintln()
"Derry老师".stringAllInfoValueVal // 扩展属性
.showPrintln().showPrintln().showPrintln().showPrintln() // 扩展函数
}
55、内置函数的总结
/**
* 内置函数的总结:
*
* TODO apply:info.apply
* 1.apply函数返回类型,永远都是info本身 此条和 also 一模一样
* 2.apply函数的 匿名函数里面持有的是this == info本身 此条和 run一模一样
*
* TODO let:集合.let
* 1.let函数返回类型,是根据匿名函数最后一行的变化而变化 此条和 run 一模一样
* 2.let函数的 匿名函数里面持有的是it == 集合本身 此条和 also 一模一样
*/
TODO run: str.run
1.run函数返回类型,是根据匿名函数最后一行的变化而变化 此条和 let一模一样
2.run函数的 匿名函数里面持有的是this == str本身 此条和 apply一模一样
TODO with with(str) with和run基本上一样,只不过就是使用的时候不同
1.with函数返回类型,是根据匿名函数最后一行的变化而变化 此条和 let一模一样
2.with函数的 匿名函数里面持有的是this == str本身 此条和 apply一模一样
TODO also str.also
1.also函数返回类型,永远都是str本身 此条和 apply 一模一样
2.also函数的 匿名函数里面持有的是it == str 此条和 let 一模一样
Todo ================================= apply 与 also 是一个类别的 属于一类的 =================================
相同点:apply与also返回类型,是一样的: 他们永远都是返回info本身,匿名函数,最后一行无法作为返回值,不影响函数返回类型
不同点:匿名函数里面 apply{ 持有this setFilexxx() } alos { 持有it it.setFilexxx() }
应用点:
val file本身 = File("xx").apply { setFilexxx() ... }.apply { ... }.apply { ... } 链式调用
val file本身 = FIle("xx").also { it.setFilexxx() ... }.also { ... }.also { ... } 链式调用
val info本身 = info.apply {
this == info本身
...
"Derry"
}.apply {
}.apply {
}
val info本身 = info.also {
it == info本身
...
true
}.also {
}.also {
}
Todo ================================= run 与 let 与 with 是一个类别的 属于一类的 =================================
相同点:run与let返回类型,是一样的,都会根据匿名函数最后一行返回类型而决定 run与let的返回类型(是根据匿名函数最后一行的变化而变化)
不同点:匿名函数里面 run持有this let持有it
应用点:
info.run { show("内容:$this") show("内容长度:$length") show("${if (this is String) 你是String类型 else 你不是String类型}") }
info.let { show("内容:it") show("内容长度:$it.length") show("${if (it is String) 你是String类型 else 你不是String类型}") }
val r : Boolean类型 = info.run { this == info本身
length
545
454.545
534543.5f
true // 最后一行
}
val r : Char类型 = info.let { it == info本身
it.length
545
454.545
534543.5f
true
'A' // 最后一行
}
TODO >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 下面是with
上面的 run 使用环节: info.run {}
下面的 with 使用环节: with(info) {}
相同点:with与run与let返回类型,是一样的,都会根据匿名函数最后一行返回类型而决定 run与let的返回类型(是根据匿名函数最后一行的变化而变化)
不同点:匿名函数里面 run持有this let持有it with持有this
应用点:
info.run { show("内容:$this") show("内容长度:$length") show("${if (this is String) 你是String类型 else 你不是String类型}") }
info.let { show("内容:it") show("内容长度:$it.length") show("${if (it is String) 你是String类型 else 你不是String类型}") }
with(info) { show("内容:this") show("内容长度:$length") show("${if (this is String) 你是String类型 else 你不是String类型}") }
TODO ======================================= let 与 apply 内部源码原理分析
// 1. let的返回类型是 根据匿名函数的变化而变化(lambda的返回类型变化而变化)
// 2. 匿名函数里面持有的是 it == I == info本身
inline fun <I, O> I.let(lambda : (I) -> O) = lambda(this)
// 1. apply的返回类型是 永远都是I(所以你可以链式调用) (lambda的返回类型 无法变化,你写的是 Unit,并且 没有和lambda关联返回类型)
// 2. 匿名函数里面持有的是 this == I == info本身
inline fun <I> I.apply(lambda : I.() -> Unit) : I {
lambda()
return this
}
56、Kotlin语言的可空类型扩展函数
package com.derry.s6
// 对 String?==可空类型的 进行函数扩展,并且有备用值
fun String?.outputStringValueFun(defalutValue : String) = println(this ?: defalutValue)
// 编译期非常智能:能够监测到你做了if判断(能够对你代码逻辑监测),就知道后续类型
fun String?.outputStringValueFunGet(defaultValue : String) = if (this == null) defaultValue else this
// TODO 118-Kotlin语言的可空类型扩展函数
// 如果是null,就输出默认值
fun main() {
val infoValue : String ? = null // infoValue是可空的类型 String String?==可空类型的
infoValue.outputStringValueFun("我是默认值啊1")
// String? 前面已经说过了,可以接收 可空数据 也可以接收 有值数据
// String 前面已经说过了,只能接收 有值数据
val name = "Derry"
name.outputStringValueFun("我是默认值啊2")
// >>>>>>>>>>>>>>
println(infoValue.outputStringValueFunGet("我是默认值啊3"))
println(name.outputStringValueFunGet("我是默认值啊4"))
}
57、Kotlin语言的infix关键字
package com.derry.s6
// 自定义的中缀表达式 + 扩展函数 一起用的 使用者: "一".gogogo(1) "一" gogogo 1
// 1.条件一 对第一个参数 C1.gogogo 函数扩展
// 2.条件二 需要在 括号(c2: C2) 参数里面,传递一个参数
private infix fun <C1, C2> C1.gogogo(c2: C2) {
// 做很多的逻辑
// ...
// 省略几万行代码
println("我们的中缀表达式,对一个参数的内容是:$this")
println("我们的中缀表达式,对二个参数的内容是:$c2")
}
// TODO 119-Kotlin语言的infix关键字
// infix == 中缀表达式 可以简化我的代码
fun main() {
// 下面是我们map自带的中缀表达式
mapOf("零".to(0))
mapOf("一" to 1)
mapOf("二" to 2)
mapOf("三" to 3)
// 下面是我们自己写的中缀表达式
123 gogogo '男'
"Derry".gogogo('M')
"Derry2" gogogo 'M'
}
58、Kotlin语言的定义扩展文件
package com.derry.s6.com.derry
// 1.扩展文件一般都是public,如果private外界无法使用
// 2.Iterable<E> 子类 set list 都可以用,所以用父类
// 3.本次扩展函数的作用是,随机取第一个元素返回
fun <E> Iterable<E>.randomItemValue() = this.shuffled().first()
fun <T> Iterable<T>.randomItemValuePrintln() = println(this.shuffled().first())
...
package com.derry.s6
// 导入扩展文件
// 在工作中非常有用,可以把很多的扩展操作,写到某一个地方,到时候引入过来用,比较独立化
import com.derry.s6.com.derry.randomItemValue
import com.derry.s6.com.derry.randomItemValuePrintln
// TODO 120-Kotlin语言的定义扩展文件
fun main() {
val list : List<String> = listOf("李元霸", "李连杰", "李小龙")
val set : Set<Double> = setOf(545.5, 434.5, 656.6)
// 如果不使用 扩展文件
println(list.shuffled().first())
println(set.shuffled().first())
println()
// 使用 扩展文件
println(list.randomItemValue())
println(set.randomItemValue())
println()
list.randomItemValuePrintln()
set.randomItemValuePrintln()
}
59、Kotlin语言的重命名扩展学习
package com.derry.s6
import com.derry.s6.com.derry.randomItemValue as g // as g 重命名扩展操作
import com.derry.s6.com.derry.randomItemValuePrintln as p // as g 重命名扩展操作
// TODO 121-Kotlin语言的重命名扩展学习
fun main() {
val list : List<String> = listOf("李元霸", "李连杰", "李小龙")
val set : Set<Double> = setOf(545.5, 434.5, 656.6)
// 使用 扩展文件
println(list.g())
println(set.g())
println()
list.p()
set.p()
}
60、Kotlin语言的DSL学习
package com.derry.s6
import java.io.File
class Context {
val info = "我就是Derry"
val name = "DDD"
fun toast(str: String) = println("toast:$str")
}
inline fun Context.apply5(lambda: Context.(String) -> Unit): Context {
lambda(info)
return this
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
inline fun File.applyFile(action: (String, String?) -> Unit): File {
setWritable(true)
setReadable(true)
action(name, readLines()[0])
return this
}
// TODO 123-Kotlin语言的DSL学习
// DSL简介 所谓DSL领域专用语言(Domain Specified Language/ DSL)
fun main() {
// 其实apply5函数,就是DSL编程范式,定义输入输出等规则:
// 1.定义整个lambda规则标准,输入 必须是Context这个类,才有资格调用apply5函数,匿名函数里面持有it 和 this
// 2.定义整个lambda规则标准,输出 我们会始终返回Context本身,所以你可以链式调用
// 然后main函数就可以根据DSL编程方式标准规则,来写具体的实现,这就是DSL编程范式
val context : Context = Context().apply5 {
// it == String == "我就是Derry"
println("我的it是:$it,我的this是:$this")
toast("success")
toast(it)
toast(name)
true
}.apply5 { }.apply5 { }.apply5 { } // ...
println()
println("我始终是输出Context本身:" + context.info)
println()
// 其实applyFile函数,就是DSL编程范式,定义输入输出等规则:
// 1.定义整个lambda规则标准,输入 必须是File类,才有资格调用applyFile函数,匿名函数里面持有 fileName,data
// 2.定义整个lambda规则标准,输出 我们始终返回File对象本身,所以你可以链式调用
// 然后main函数就可以根据DSL编程方式标准规则,来写具体的实现,这就是DSL编程范式
val file: File = File("D:\\a.txt")
.applyFile { fileName, data ->
println("你的文件名是:$fileName, 你的文件里面的数据是:$data")
println("你的文件名是:$fileName, 你的文件里面的数据是:$data")
println("你的文件名是:$fileName, 你的文件里面的数据是:$data")
true
}.applyFile { a, b -> }.applyFile { a, b -> }.applyFile { a, b -> } // ...
println("我始终是输出File本身:${file.name}")
}
61、Kotlin语言的变换函数-map
package com.derry.s6
// TODO 124-Kotlin语言的变换函数-map
fun main() {
val list = listOf("李元霸", "李连杰", "李小龙")
// T T T ---> 新的集合(R, R, R)
// 原理:就是把你 匿名函数 最后一行的返回值 加入一个新的集合,新集合的泛型是R,并且返回新集合
val list2 : List<Int> = list.map {
// it = T == 元素 == String
"【$it】"
88
}
println(list2)
// 用途: 和 RxJava的思路,一模一样
val list3 : List<String> = list.map {
"姓名是:$it"
}.map {
"$it,文字的长度是:${it.length}"
}.map {
"【$it】"
}
for (s in list3) {
print("$s ")
}
println()
list.map {
"姓名是:$it"
}.map {
"$it,文字的长度是:${it.length}"
}.map {
"【$it】"
}.map {
print("$it ")
}
}
62、Kotlin语言的变换函数-flatMap
package com.derry.s6
// TODO 125-Kotlin语言的变换函数-flatMap
// map {返回类型:T String Int Boolean Char ... 是把每一个元素(String)加入到新集合,最后返回新集合 List<String>}
// flatMap {返回类型:每一个元素 T 集合1 集合2 集合3 ... 是把每一个元素(集合)加入到新集合,最后返回新集合 List<List<String>> 最终内部会处理成List<String>}
// TODO flatMap 相当于 List<List<String>> 集合的集合,有嵌套关系
fun main() {
val list : List<String> = listOf("李四", "王五", "赵六", "初七")
val newList : List<String> = list.map {
"你的姓名是:$it" // 每次返回一个 String
}.map {
"$it, 你文字的长度是:${it.length}" // 每次返回一个 String
}.flatMap {
listOf("$it 在学习C++", "$it 在学习Java", "$it 在学习Kotlin") // 每次返回一个集合,四次
}
println(newList)
println()
/*
[你的姓名是:李四, 你文字的长度是:8 在学习C++,
你的姓名是:李四, 你文字的长度是:8 在学习Java,
你的姓名是:李四, 你文字的长度是:8 在学习Kotlin,
你的姓名是:王五, 你文字的长度是:8 在学习C++,
你的姓名是:王五, 你文字的长度是:8 在学习Java,
你的姓名是:王五, 你文字的长度是:8 在学习Kotlin,
你的姓名是:赵六, 你文字的长度是:8 在学习C++,
你的姓名是:赵六, 你文字的长度是:8 在学习Java,
你的姓名是:赵六, 你文字的长度是:8 在学习Kotlin,
你的姓名是:初七, 你文字的长度是:8 在学习C++,
你的姓名是:初七, 你文字的长度是:8 在学习Java,
你的姓名是:初七, 你文字的长度是:8 在学习Kotlin]
*/
val newList2 : List<String> = list.flatMap {
listOf("$it 在学习C++", "$it 在学习Java", "$it 在学习Kotlin")
}
println(newList2)
//[李四 在学习C++,
// 李四 在学习Java,
// 李四 在学习Kotlin,
// 王五 在学习C++,
// 王五 在学习Java,
// 王五 在学习Kotlin,
// 赵六 在学习C++,
// 赵六 在学习Java,
// 赵六 在学习Kotlin,
// 初七 在学习C++,
// 初七 在学习Java,
// 初七 在学习Kotlin]
// 原理:就是把你 匿名函数 最后一行的返回值(又是一个集合listOf(......)) 加入一个新的集合,新集合的泛型是R,并且返回新集合
}
63、Kotlin语言的合并函数-zip
package com.derry.s6
// TODO 127-Kotlin语言的合并函数-zip
fun main() {
val names = listOf("张三", "李四", "王五")
val ages = listOf(20, 21, 22)
// RxJava zip 合并操作符
// KT 自带就有zip 合并操作
// 原理:就是把 第一个集合 和 第二个集合 合并起来,创建新的集合,并返回
// 创建新的集合(元素,元素,元素) 元素Pair(K, V) K代替第一个集合的元素 V代替第二个集合的元素
val zip : List<Pair<String, Int>> = names.zip(ages)
println(zip)
println(zip.toMap())
println(zip.toMutableSet())
println(zip.toMutableList())
println()
// 遍历
zip.forEach {
// it == Pair<String, Int>
println("姓名是:${it.first}, 年龄是:${it.second}")
}
println()
// map 普通方式
zip.toMap().forEach { k, v ->
println("姓名是:${k}, 年龄是:${v}")
}
println()
// map 解构的方式
zip.toMap().forEach { (k, v) ->
println("姓名是:${k}, 年龄是:${v}")
}
println()
zip.toMap().forEach {
// it == Map的元素 每一个元素 有K和V, Map.Entry<String, Int>
// it == Pair<String, Int>
println("姓名是:${it.key}, 年龄是:${it.value}")
}
}
64、Kotlin 单例
// 1.饿汉式的实现 KT版本
object SingletonDemoKt
// 2.懒汉式的实现 KT版本
class SingletonDemo2Kt {
companion object {
private var instance : SingletonDemo2Kt? = null
get() {
if (field == null) {
field = SingletonDemo2Kt()
}
return field
}
fun getInstanceAction() = instance!!
}
fun show() {
println("show")
}
}
fun main() {
SingletonDemo2Kt.getInstanceAction().show()
}
// 3.懒汉式的实现 KT版本 安全
class SingletonDemo3Kt {
companion object {
private var instance : SingletonDemo2Kt? = null
get() {
if (field == null) {
field = SingletonDemo2Kt()
}
return field
}
@Synchronized
fun getInstanceAction() = instance!!
}
fun show() {
println("show")
}
}
fun main() {
SingletonDemo3Kt.getInstanceAction().show()
}
// 4.懒汉式的实现 双重校验安全 KT版本
class SingletonDemo4Kt private constructor() {
companion object {
val instance : SingletonDemo4Kt by lazy (mode = LazyThreadSafetyMode.SYNCHRONIZED) { SingletonDemo4Kt() }
}
fun show() {
println("show")
}
}
fun main() {
SingletonDemo4Kt.instance.show()
}
65、注解@JvmName与Kotlin
@file:JvmName("Stu") // 就是在编译器环节,修改我们的类的名字,让Java端调用更简洁
package com.derry.s7
// @file:JvmName("Stu") 注意:必须写在 包名的外面
// TODO 131-注解@JvmName与Kotlin
fun getStudentNameValueInfo(str : String) = println(str)
fun main() {}
/* 背后生成的代码:
public final class KtBase131Kt {
public static final void getStudentNameValueInfo(@NotNull String str) {
System.out.println(str);
}
public static final void main() {
}
public static void main(String[] args) {
main();
}
}
@file:JvmName("Stu") 背后的原理
public final class Stu {
public static final void getStudentNameValueInfo(@NotNull String str) {
System.out.println(str);
}
public static final void main() {
}
public static void main(String[] args) {
main();
}
}
*/
public class KtBase131 {
public static void main(String[] args) {
// KtBase131Kt.getStudentNameValueInfo("Derry is OK");
//java端调用
Stu.getStudentNameValueInfo("Derry is OK a");
}
}
66、注解@JvmField与Kotlin
// TODO 132.注解@JvmField与Kotlin
class Person {
@JvmField
val names = listOf("Zhangsan", "Lisi", "Wangwu")
}
/* 背后的原理代码:
public final class Person{
@NotNull
private final List names = CollectionsKt.listOf(new String[]{"Zhangsan", "Lisi", "Wangwu"});
// val 只读的,只有 getNames
public final List getNames() {
return this.names;
}
}
@JvmField 背后会剔除私有代码 成员
public final class Person {
@JvmField
@NotNull
public final List names = CollectionsKt.listOf(new String[]{"Zhangsan", "Lisi", "Wangwu"});
}
*/
public class KtBase132 {
public static void main(String[] args) {
Person person = new Person();
//加上JvmField 可以直接调用属性
for (String name : person.names) {
System.out.println(name);
}
}
}
67、注解@JvmOverloads与Kotlin
//kotlin
// 默认参数
fun show( name : String, age : Int = 20, sex : Char = 'M') {
println("name:$name, age:$age, sex:$sex")
}
// 默认参数
@JvmOverloads // 原理:编译器环节 专门重载一个函数,专门给 Java用
fun toast( name : String, sex : Char = 'M') {
println("name:$name, sex:$sex")
}
// TODO 133-注解@JvmOverloads与Kotlin
fun main() {
// KT端
show("张三")
toast("李四")
}
//java
public class KtBase133 {
public static void main(String[] args) {
// Java端
// KtBase133Kt.show("张三") // Java无法享用 KT的默认参数
KtBase133Kt.toast("张三"); // 相当于 Java 享用 KT的默认参数
}
}
68、注解@JvmStatic与Kotlin关系
class MyObject {
companion object {
@JvmField
val TARGET = "黄石公园"
@JvmStatic
fun showAction(name: String) = println("$name 要去 $TARGET 玩")
}
}
// TODO 134-注解@JvmStatic与Kotlin关系
fun main() {
// KT 端
MyObject.TARGET
MyObject.showAction("Derry")
}
public class KtBase134 {
public static void main(String[] args) {
// Java 端
//加上@JvmField,java可以直接调用成员变量属性
System.out.println(MyObject.TARGET);
//加上@JvmStatic,java可以直接调用函数
MyObject.showAction("Kevin");
}
}
网友评论