文章目录
1.空检查
?:表示为空则不执行后面
!!:表示一定执行后面
// TODO 第一种情况:默认是不可空类型,所以不能给null
var name: String = "Derry"
// 提示:不能是非空类型String的值
// name = null
println(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 = 6
println("今天天气很晴朗,去玩" + garden + ",玩了" +time +" 小时") // Java的写法
println("今天天气很晴朗,去${garden}玩,玩了$time 小时") // 字符串模版的写法
// KT的if是表达式,所以可以更灵活, Java的if是语句,还有局限性
val isLogin = false
println("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)//5
val len2 = "Derry".count {
// it 等价于 D e r r y 的字符 Char
it == '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 = 999999
return "$inputValue Derry 参数一:$number1, 参数二:$number2, 参数三:$number3"
}
*/
3.it关键字
fun main() {
val methodAction : (Int, Int, Int) -> String = { n1, n2, n3 ->
val number = 24364
println("$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 Derry
val 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) -> String
println(method1(454.5, 354.3f, 99))
val method2 = {
3453.3f
} // method2 函数: () -> Unit
println(method2())
val method3 = { number: Int ->
number
} // method3 函数: (Int) -> Int
println(method3(9))
}
5.lambda学习
fun main() {
// 匿名函数 == lambda表达式
val addResultMethod = { number1 : Int, number2: Int ->
"两数相加的结果是:${number1 + number2}"
} // addResultMethod 函数: (Int, Int) -> String
println(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) -> Any
println(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() {
@Override
public 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;
else
return 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")
}
// 具名函数 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写法
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);
}
}
13.操作符
1.let
fun main() {
var name: String? = null
name = "Derry"
name = ""
// name是可空类型的 如果真的是null,?后面这一段代码不执行,就不会引发空指针异常
val r =name?.let {
// it == name 本身
// 如果能够执行到这里面的,it 一定不为null
if (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 + value1
println(result1) //12
// let方式 对集合第一个元素相加
val result2 = listOf(6, 5, 2, 3, 5, 7).let {
// it == list集合
it.first() + it.first() // 匿名函数的最后一行,作为返回值,let的特点, 但是前面学的apply永远是返回info本身
/*true
true
true*/
}
println(result2) //12
println()
// 普通方式 对值判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? = null
checkException(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 ? = null
var value2: Boolean = false
// 经常使用来检测是否为null
// checkNotNull(value1) // java.lang.IllegalStateException: Required value was null.
// requireNotNull(value1) // java.lang.IllegalArgumentException: Required value was null.
// 经常使用来检测是否为true
require(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) = list
println("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,java
println(name1 == name2) // true,kt
// 引用的比较
println(name1 === name2) // true
println(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) //null
val number3: Int? = "888".toIntOrNull()
println(number3) //888
val number4: Int? = "888.8".toIntOrNull()
println(number4 ?: "原来你是null啊")
}
11.roundToInt()
fun main() {
println(65.4645654.toInt()) // 65
println(65.8343433.roundToInt()) // 65
println(65.4645654.roundToInt()) // 65 四舍五入
println(65.8343433.roundToInt()) // 66 四舍五入
// 结论:用 roundToInt()函数,保证 Double ->转Int 持有四舍五入的效果
// r的类型: String
val r = "%.3f".format(65.8343433)
println(r) //65.834
}
12.apply、
特点:持有this,本身作为返回值
fun main() {
val info = "Derry You Hao"
// 普通的方式
println("info字符串的长度是:${info.length}") //13
println("info最后一个字符是:${info[info.length -1]}") //o
println("info全部转成小写是:${info.toLowerCase()}") //derry you hao
println()
// apply内置函数的方式
// info.apply特点:apply函数始终是返回 info本身 String类型
val infoNew : String = info.apply {
// 一般大部分情况下,匿名函数,都会持有一个it,但是apply函数不会持有it,却会持有当前this == info本身
println("apply匿名函数里面打印的:$this") //Derry You Hao
println("info字符串的长度是:${length}") //13
println("info最后一个字符是:${this[length -1]}") //o
println("info全部转成小写是:${toLowerCase()}") //derry you hao
}
println("apply返回的值:$infoNew") //Derry You Hao
println()
// 真正使用apply函数的写法规则如下:
// info.apply特点:apply函数始终是返回 “本身”,所以可以链式调用
info.apply {
println("长度是:$length") //13
}.apply {
println("最后一个字符是:${this[length -1]}") //o
true
true
true
}.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 + value1
println(result1)//12
// let方式 对集合第一个元素相加
val result2 = listOf(6, 5, 2, 3, 5, 7).let {
// it == list集合
it.first() + it.first() // 匿名函数的最后一行,作为返回值,let的特点, 但是前面学的apply永远是返回info本身
/*true
true
true*/
}
println(result2)//12
println()
// 普通方式 对值判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本身
true
5435.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 false
fun 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)//3
val r2 = with(r1, ::getLenInfo)//你的字符串长度是:3
val 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? = null
fun getInfoValue() /* : String? */ = infoValue
fun 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.elementAtOrElse
4.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表示只读的,不能赋值;赋值可以使用var
println("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 intArrayOf
DoubleArray doubleArrayOf
LongArray longArrayOf
ShortArray shortArrayOf
ByteArray byteArrayOf
FloatArray floatArrayOf
BooleanArray booleanArrayOf
Array<对象类型> 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 111
map -= "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 {
@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();
}
}
*/
}
// 伴生对象的由来: 在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 = _bodyInfo
fun 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@266474c2
println(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() = name
operator fun component2() = age
operator 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.limbsInfo
this.limbsInfo.length = limbsInfo.length
println("更新后的数据是:${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()) // 对象2
println(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() = 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"
}
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 不能写set
val usbInsertDevice: String // USB插入的设备信息
get() = "高级设备接入USB"
// val 不需要set
fun insertUBS() : String
}
// 鼠标UBS实现类
class Mouse2 : USB2 {
override val usbInsertDevice: String
get() = super.usbInsertDevice
override val usbVersionInfo: String
get() = super.usbVersionInfo
override 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(): Int
abstract fun initView()
abstract fun initData()
abstract fun initXXX()
}
class LoginActivity : BaseActivity() {
override fun getLayoutID(): Int = 564
override 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.泛型
-
Java SE 1.5的才有的特性,本质是参数化类型,泛型分为
泛型类
、泛型接口
、泛型方法
。
在没有泛型的情况的下只能通过对Object 的引用来实现参数的任意化
没泛型的缺点:要显式的强制类型转换,而强制转换在编译期是不做检查的,容易把问题留到运行时
泛型优点:在编译时检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率,避免在运行时出现 ClassCastException -
泛型实现原理:泛型擦除
编译器在编译期对字节码时先进行类型检查,再进行类型擦除所有泛型类型相关信息(即所有类型参数都用限定类型替换,包括类、变量和方法。如果类型变量有限定则原始类型就用第一个边界的类型来替换,譬如 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之后才能使用 }
-
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)
-
reified
在inline函数中通过reified关键字来标记这个泛型在编译时替换成具体类型 -
泛型使用示例
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 T java.lang.Long::class.java -> bundle.getLong(key) as T java.lang.String::class.java -> bundle.getString(key) as T java.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 T else -> 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是否为Int 1L 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() //万能输出器:575
KtBase103(53456.45).show() //万能输出器:53456.45
KtBase103(4645.5f).show() //万能输出器:4645.5
KtBase103('男').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啊") // 返回Unit
println(r) //545.4
println()
// 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万能对象是:Derry
show(null) //show,你万能对象返回器,是返回null啊
println()
show2("Derry")
//show2,万能对象是:Derry
//show2: 你传递进来的r:Derry
show2(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 = item
var r : B? = item ?.also {
if (it == null) {
println("show2,你万能对象返回器,是返回null啊")
} else {
println("show2,万能对象是:$it")
}
} ?: null
println("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 有可能是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.toString() // lambda最后一行是 返回值
"我的it是:$it" // lambda最后一行是 返回值
}
// 4.验证是否是此类型 与 null
println(r is String) //false
println(r is String?) //true
println(r ?: "大哥你是null,你在搞什么飞机...,你是不是传入了isMap是false") //大哥你是null,你在搞什么飞机...,你是不是传入了isMap是false
println()
// 3.map per -> stu 最终接收是什么类型
val p2 = KtBase105(true, Persons("李四", 99))
val r2 : Students? = p2.map {
// it == Persons对象 == inputType
Students(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))//Derry
println(p.showObj(1))//false
println(p.showObj(2))//53454
println(p.showObj(3))//4543.3
println(p.showObj(4)) // 4554.54
println(p.showObj(5)/*?.特殊操作 如果是null 会引发奔溃*/) // null
println(p.showObj(6)) // C
println()
// mapObj
// it类型 {Comparable<*> & java.io.Serializable} 需要转换一下才行 例如:it.toString
val r : Int = p.mapObj(0) {
it
it.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,居然也可以,因为out
val p3 : Producer<Animal> = ProducerClass3() // ProducerClass3他本来就是 传递 Man,居然也可以,因为out
val p1 : Consumer<Man> = ConsumerClass1() // ConsumerClass1他本来就是 传递 Animal,居然也可以,因为in
val 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() // 省略this
return 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类型
// 万能类型,任何类型,所有类型,都可以使用我的 mLet
val r2 : String = "Derry2".let {
it
34543.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: String
get() = "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) //300
private 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.0
infix fun add(amount: Double) : Unit {
this.balance = balance + amount
}
}
val account = Account()
account add 100.00
print(account.balance) //200