60、Kotlin的主构造函数
// 主构造函数:规范来说,都是增加_xxx的方式,临时的输入类型,不能直接用,需要接收下来 成为变量才能用
// _name 等等,都是临时的类型,不能直接要弄,需要转化一下才能用
class KtBase60(_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)
}
}
fun main() {
// KtBase60()
val p = KtBase60(_name = "Zhangsan", _info = "学习KT语言", _age = 88, _sex = 'M')
// println(p.name)
// p.name = "AAA" 被私有化了,不能调用
p.show()
}
61、Kotlin的主构造函数里定义属性
// var name: String 就相当于 var name = _name 这不过你看不到而已
// 一步到位,不像我们上一篇是分开写的
class KtBase61 (var name: String, val sex: Char, val age: Int, var info: String)
{
fun show() {
println(name)
println(sex)
println(age)
println(info)
}
}
fun main() {
KtBase61(name = "Zhangsan", info = "学习KT语言", age = 88, sex = 'M').show()
}
62、Kotlin的次构造函数
class KtBase62(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")
}
}
// name: String, sex: Char, age: Int, info: String
fun main() {
val p = KtBase62("李元霸") // 调用主构造
KtBase62("张三", '男') // 调用 2个参数的次构造函数
KtBase62("张三2", '男', 88) // 调用 3个参数的次构造函数
KtBase62("张三3", '男', 78, "还在学习新语言") // 调用 4个参数的次构造函数
}
63、Kotlin的构造函数中默认参数
class KtBase63(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")
}
}
fun main() {
val p = KtBase63("李元霸2") // 调用主构造
KtBase63("张三", '男') // 调用 2个参数的次构造函数
KtBase63("张三2", '男', 88) // 调用 3个参数的次构造函数
KtBase63("张三3", '男', 78, "还在学习新语言") // 调用 4个参数的次构造函数
KtBase63() // 到底是调用哪一个 构造函数,是次构造 还是 主构造 ? 答:优先调用主构造函数
}
64、Kotlin的初始化块
// username: String, userage: Int, usersex: Char 临时类型,必须要二次转换,才能用
class KtBase64 (username: String, userage: Int, usersex: Char) // 主构造
{
// 这个不是Java的 static{}
// 相当于是Java的 {} 构造代码块
// 初始化块 init代码块
init {
println("主构造函数被调用了 $username, $userage, $usersex")
// 如果第一个参数是false,就会调用第二个参数的lambda
// 判断name是不是空值 isNotBlank ""
require(username.isNotBlank()) { "你的username空空如也,异常抛出" }
require(userage > 0) { "你的userage年龄不符合,异常抛出" }
require( usersex == '男' || usersex == '女') { "你的性别很奇怪了,异常抛出" }
}
constructor(username: String) : this(username, 87, '男') {
println("次构造函数被调用了")
}
fun show() {
// println(username) // 用不了,必须要二次转换,才能用
}
}
// 1.name,age,sex的主构造函数
// 2.init代码块学习 require
// 3.临时类型只有在 init代码块才能调用
fun main() {
KtBase64 ("李四", userage = 88, usersex = '女') // 调用主构造
println()
KtBase64 ("王五") // 调用次构造
// KtBase64 ("") // 调用次构造
// KtBase64 ("李四", userage = -1, usersex = 'M') // 调用主构造
KtBase64 ("李四", userage = 1, usersex = '男') // 调用主构造
}
65、Kotlin的构造初始化顺序
// 第一步:生成val sex: Char
class KtBase65(_name: String, val sex: Char) // 主构造
{
// 第二步: 生成val mName // 由于你是写在 init代码块前面,所以先生成你, 其实类成员 和 init代码块 是同时生成
val mName = _name
init {
val nameValue = _name // 第三步:生成nameValue细节
println("init代码块打印:nameValue:$nameValue")
}
// 次构造 三个参数的 必须调用主构造
constructor(name: String, sex: Char, age: Int) :this(name, sex) {
// 第五步:生成次构造的细节
println("次构造 三个参数的, name:$name, sex:$sex, age:$age")
}
// 第四步
val Merry = "AAA"
// 纠正网上优秀博客的错误: 类成员先初始生成 再init代码块初始生成 错误了
// Merry 正确说法:init代码块 和 类成员 是同时的,只不过你写在 init代码块前面 就是先生成你
}
// 1.main 调用次构造 name sex age
// 2.主构造的 val 变量
// 3.var mName = _name
// 4.init { nameValue 打印 }
fun main() {
// 调用次构造
KtBase65("李元霸", '男', 88) // 调用次构造
}
66、Kotlin的延迟初始化lateinit
::变量名.isInitialized 判断变量是否初始化
class KtBase66 {
// 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("你都没有初始化加载,你是不是忘记加载了")
}
}
}
// 1.lateinit responseResultInfo 定义
// 2.request 懒加载
// 3.showResponseResult
// 4.main 先请求 在显示
fun main() {
val p = KtBase66()
// 使用他之前,加载一下(用到它才加载,就属于,懒加载)
p.loadRequest()
// 使用他
p.showResponseResult()
}
67、Kotlin的惰性初始化by lazy
变量使用的时候才会加载
class KtBase67 {
// >>>>>>>>>>>>>>>>>>> 下面是 不使用惰性初始化 by lazy 普通方式(饿汉式 没有任何懒加载的特点)
// val databaseData1 = readSQlServerDatabaseAction()
// >>>>>>>>>>>>>>>>>>> 使用惰性初始化 by lazy 普通方式
val databaseData2 by lazy { readSQlServerDatabaseAction() }
private fun readSQlServerDatabaseAction(): String {
println("开始读取数据库数据中....")
println("加载读取数据库数据中....")
println("加载读取数据库数据中....")
println("加载读取数据库数据中....")
println("加载读取数据库数据中....")
println("加载读取数据库数据中....")
println("加载读取数据库数据中....")
println("加载读取数据库数据中....")
println("加载读取数据库数据中....")
println("结束读取数据库数据中....")
return "database data load success ok."
}
}
// TODO 79.Kotlin语言的惰性初始化by lazy学习
// 1.不使用惰性初始化 databaseData1 = readSQLServerDatabaseAction()
// 2.使用惰性初始化 databaseData2 by lazy
// 3.KtBase82() 睡眠 db1.databaseData1
// lateinit 是在使用的时候,手动加载的懒加载方式,然后再使用
// 惰性初始化by lazy 是在使用的时候,自动加载的懒加载方式,然后再使用
fun main() {
// >>>>>>>>>>>>>>>>>>> 下面是 不使用惰性初始化 by lazy 普通方式(饿汉式 没有任何懒加载的特点)
/*val p = KtBase67()
Thread.sleep(5000)
println("即将开始使用")
println("最终显示:${p.databaseData1}")*/
// >>>>>>>>>>>>>>>>>>> 使用惰性初始化 by lazy 普通方式
val p = KtBase67()
Thread.sleep(5000)
println("即将开始使用")
println("最终显示:${p.databaseData2}")
}
68、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())
}
// 1.父类 val name showName()->String myPrintln->Unit
// 2.子类 myPrintln->Unit
fun main() {
val person: Person = Student("张三")
person.myPrintln()
}
69、Kotlin语言的类型转换 (is / is+as)
open class Person2(private val name: String) {
fun showName() = "父类 的姓名是【$name】"
// KT所有的函数,默认是final修饰的,不能被重写,和Java相反
open fun myPrintln() = println(showName())
}
class Student2(private val subName: String) : Person2(subName) {
fun showName2() = "子类 的姓名是【${subName}】"
override fun myPrintln() = println(showName2())
}
// 1.普通运行子类输出
// 2.is Person Student File
// 3.is + as 转换
fun main() {
val p: Person2 = Student2("王五")
p.myPrintln()
println(p is Person2)
println(p is Student2)
println(p is File)
// is + as = 一般是配合一起使用
if (p is Student2) {
(p as Student2).myPrintln()
}
if (p is Person2) {
// (p as Person2).myPrintln() // 因为子类重写了父类
println((p as Person2).showName())
}
}
70、Kotlin的Any超类
- 在KT中,所有的类,都隐士继承了 : Any() ,你不写,默认就有
- Any类在KT设计中:只提供标准,你看不到实现,实现在各个平台处理好了
71、Kotlin的对象声明
- object KtBase71 既是单例的实例,也是类名
- 小结:既然是 单例的实例,又是类名,只有一个创建,这就是典型的单例
object KtBase71 {
init {
println("KtBase71 init...")
}
fun show() = println("我是show函数...")
}
fun main() {
// object KtBase71 既是单例的实例,也是类名
// 小结:既然是 单例的实例,又是类名,只有一个创建,这就是典型的单例
println(KtBase71 ) // 背后代码:println(KtBase71 .INSTANCE)
println(KtBase71 ) // 背后代码:println(KtBase71 .INSTANCE)
// 背后代码:KtBase71 .INSTANCE.show();
println(KtBase71 .show())
}
72、Kotlin的对象表达式
小结:Java接口,有两种方式 1(object : 对象表达式) 2简洁版,
KT接口,只有一种方式 1(object : 对象表达式)
interface RunnableKT {
fun run()
}
open class KtBase72 {
open fun add(info: String) = println("KtBase72 add:$info")
open fun del(info: String) = println("KtBase72 del:$info")
}
// 1.add del println
// 2.匿名对象表达式方式
// 3.具名实现方式
// 4.对Java的接口 用对象表达式方式
fun main() {
// 匿名对象 表达式方式
val p : KtBase72 = object : KtBase72 () {
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 = KtBase72Impl()
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 : 对象表达式)
// 具名实现 具体名字 == KtBase72Impl
class KtBase72Impl : KtBase72() {
override fun add(info: String) {
// super.add(info)
println("我是具名对象 add:$info")
}
override fun del(info: String) {
// super.del(info)
println("我是具名对象 del:$info")
}
}
73、Kotlin的伴生对象 companion object{}
伴生对象的由来: 在KT中是没有Java的这种static静态,伴生很大程度上和Java的这种static静态 差不多的
class KtBase73 {
// 伴生对象
companion object {
val info = "MerryINfo"
fun showInfo() = println("显示:$info")
val name = "Merry"
}
}
// 伴生对象的由来: 在KT中是没有Java的这种static静态,伴生很大程度上和Java的这种static静态 差不多的
// 无论 KtBase73() 构建对象多少次,我们的伴生对象,只有一次加载
// 无论 KtBase73.showInfo() 调用多少次,我们的伴生对象,只有一次加载
// 伴生对象只会初始化一次
fun main() {
// 背后代码:System.out.println(KtBase73.Companion.getInfo())
println(KtBase73.info)
// 背后代码:System.out.println(KtBase73.Companion.getName())
println(KtBase73.name)
// 背后代码:KtBase73.Companion.showInfo()
KtBase73.showInfo()
// new KtBase73();
KtBase73()
KtBase73()
KtBase73()
KtBase73()
// ...
}
74、kotlin的嵌套类
(1)内部类的特点: 内部的类 能访问 外部的类
外部的类 能访问 内部的类
(2)默认情况下:就是嵌套类关系
嵌套类特点:外部的类 能访问 内部的嵌套类
内部的类 不能访问 外部类的成员
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")
}
}
}
//嵌套类
class Outer {
val info: String = "OK"
fun show() {
Nested().output()
}
class Nested {
fun output() = println("嵌套类")
}
}
fun main() {
// 内部类:
Body("isOK").Heart().run()
Body("isOK").Hand().LeftHand().run()
Body("isOK").Hand().RightHand().run()
// 嵌套类:
Outer.Nested().output()
}
75、Kotlin的数据类
- 普通类 set get 构造函数
- 数据类--一般是用于 JavaBean的形式下,用数据类 set get 构造函数 解构操作 copy toString hashCode equals 数据类 生成 更丰富
// 普通类
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 数据类 生成 更丰富
// 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函数(对值的比较)
}
76、Kotlin的copy函数
注意事项:使用copy的时候,由于内部代码只处理主构造,所以必须考虑次构造的内容
data class KtBase76 (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 "KtBase76(name=" + this.name + ", age=" + this.age + ")";
}
*/
fun main() {
val p1 = KtBase76("李元霸") // 调用次构造初始化对象
println(p1)
val newP2 = p1.copy("李连杰", 78)
println(newP2)
// copy toString hashCode equals 等等... 主管主构造,不管次构造
}
77、Kotlin的解构声明
// 普通类
class Student1(var name: String , var age: Int, var sex: Char) {
// 注意事项:顺序必须是 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")
val(name1, age1, sex1) = Student2Data("李四", 89, '男')
println("数据类 结构后:name:$name1, age:$age1, sex:$sex1")
val(_, age2, _) = Student1("李四", 89, '男')
println("数据类 结构后: age2:$age2")
}
78、Kotlin的运算符重载
- 重载的修饰符是
operator
- 请注意,一定要用
operator
关键字修饰,否则我们是不能用+
号的
// 写一个数据类,就是为了,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, 1) + AddClass2(2, 2))
}
表示 | 重载 |
a = a + b | a = a.plus(b) |
a = a - b | a = a.minus(b) |
a = a * b | a = a.tiems(b) |
a = a / b | a = a.div(b) |
a = a % b | a = a.rem(b) |
a … b | a.rangTo(b) |
a % b | a.rem(b) 或 a.mod(b) |
++a, a++ | inc |
!a | not |
a > b | a.compareTo(b) > 0 |
a < b | a.compareTo(b) < 0 |
a >= b | a.compareTo(b) >= 0 |
a <= b | a.compareTo(b) <= 0 |
a in b | b.contains(a) |
a !in b | !b.contains(a) |
Kotlin中的 && 、 || 、 ?: 、 === 、 !== 是不能被重载的
79、Kotlin的枚举类
// KT想表达:枚举其实也是一个class,为什么,就是为了 枚举可以有更丰富的功能
enum class Week {
星期一,
星期二,
星期三,
星期四,
星期五,
星期六,
星期日
}
fun main() {
println(Week.星期一)
println(Week.星期四)
// 枚举的值 等价于 枚举本身
println(Week.星期二 is Week) //true
}
80、Kotlin的枚举类定义函数
// 四肢信息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}")
}
}
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))
}
81、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 其他,所以不需要写
}
}
// 1.定义枚举Exam类,四个级别分数情况
// 2.定义Teacher老师类,when使用枚举类
// 3.需求 得到优秀的孩子姓名
fun main() {
println(Teacher(Exam.Fraction1).show())
println(Teacher(Exam.Fraction3).show())
}
82、Kotlin的密封类 sealed
// 密封类,我们成员, 就必须有类型 并且 继承本类
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}"
}
}
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
}
83、数据类使用条件
- 条件一:服务器请求回来的响应的 JavaBean LoginResponseBean 基本上可以使用 数据类
- 条件二:数据类至少必须有一个参数的主构造函数
- 条件三:数据类必须有参数, var val 的参数
- 条件四:数据类不能使用 abstract,open,sealed,inner 等等 修饰 (数据类,数据载入的事情 数据存储)
- 条件五:需求 比较,copy,toString,解构,等等 这些丰富的功能时,也可以使用数据类
84、Kotlin的接口定义
1.接口里面的所有成员 和 接口本身 都是 public open 的,所以不需要open,这个是接口的特殊
2.接口不能有主构造,反正就是没有构造
3.实现类不仅仅要重写接口的函数,也要重写 接口的成员
4.接口实现代码区域,全部都要增加 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())
println()
val iusb2: IUSB = KeyBoard()
println(iusb2.insertUBS())
iusb2.usbInsertDevice = "AAA"
}
85、Kotlin语言的接口的默认实现
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
}
// 鼠标UBS实现类
class Mouse2 : USB2 {
override val usbInsertDevice: String
get() = super.usbInsertDevice
override val usbVersionInfo: String
get() = super.usbVersionInfo
override fun insertUBS() = "Mouse $usbVersionInfo, $usbInsertDevice"
}
// 1.注意:这样做是不对的,因为接口成员本来就是用来声明标准的
// 但是可以在接口成员声明时,完成对接口成员的实现
fun main() {
val iusb1 = Mouse2()
println(iusb1.insertUBS())
}
86、Kotlin的抽象类(abstract)
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 MainActivity : BaseActivity() {
override fun getLayoutID(): Int = 564
override fun initView() = println("做具体初始化View的实现")
override fun initData() = println("做具体初始化数据的实现")
override fun initXXX() = println("做具体初始化XXX的实现")
fun show() {
super.onCreate()
}
}
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()
}
}
fun main() = LoginActivity().show()
87、Kotlin的定义泛型类
class KtBase87<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)
// 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, '女')
KtBase87(stu1).show()
KtBase87(stu2).show()
KtBase87(tea1).show()
KtBase87(tea2).show()
KtBase87(String("刘一".toByteArray())).show()
KtBase87(575).show()
KtBase87(53456.45).show()
KtBase87(4645.5f).show()
KtBase87('男').show()
}
88、Kotlin的泛型函数
// 1.万能对象返回器 Boolean来控制是否返回 运用 takeIf
class KtBase104<T>(private val isR: Boolean, private val obj: T) {
fun getObj() : T? = obj.takeIf { isR }
}
// 1.万能对象返回器 Boolean来控制是否返回 运用 takeIf
// 2.四个对象打印
// 3.对象打印 + run + ?:
// 4.对象打印 + apply + ?:
// 5.show(t: T) + apply + ?:
fun main() {
val stu1 = Student("张三", 88, '男')
val stu2 = Student("李四", 78, '女')
val tea1 = Teacher("王五", 77, '男')
val tea2 = Teacher("赵六", 89, '女')
// 2.四个对象打印
println(KtBase104(true, stu1).getObj())
println(KtBase104(true, stu2).getObj())
println(KtBase104(true, tea1).getObj())
println(KtBase104(true, tea2).getObj())
println(KtBase104(false, tea2).getObj() ?: "大哥,你万能对象返回器,是返回null啊")
println()
// 3.对象打印 + run + ?:
val r : Any = KtBase104(true, stu1).getObj() ?.run {
// 如果 getObj 返回有值,就会进来
// this == getObj本身
println("万能对象是:$this") // 返回Unit
545.4f // 返回Float
} ?: println("大哥,你万能对象返回器,是返回null啊") // 返回Unit
println(r)
println()
// apply特点:永远都是返回 getObj.apply getObj本身
val r2 : Student = KtBase104(true, stu2).getObj().apply { }!!
println("r2:$r2")
// 4.对象打印 + apply + ?:
val r3: Teacher = KtBase104(true, tea1).getObj() .apply {
// this == getObj本身
if (this == null) {
println("大哥,你万能对象返回器,是返回null啊")
} else {
println("万能对象是:$this")
}
}!!
println("r3:$r3")
println()
show("Derry")
show("Kevin")
show("OK")
show(null)
println()
show2("111")
show2("222")
show2("OK")
show2(null)
}
// 5.show(t: T) + also + ?:
fun <B> show(item: B) {
item ?.also {
// it == item本身
println("万能对象是:$it")
} ?: println("大哥,你万能对象返回器,是返回null啊")
}
fun <B> show2(item: B) {
// var r0 = item
var r : B? = item ?.also {
if (it == null) {
println("大哥,你万能对象返回器,是返回null啊")
} else {
println("万能对象是:$it")
}
} ?: null
println("show2: 你传递进来的r:$r")
}
89、Kotlin的泛型变换实战
// 1.类 isMap map takeIf map是什么类型
class KtBase89<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
// 1.类 isMap map takeIf map是什么类型
// 2.map int -> str 最终接收是什么类型
// 3.map per -> stu 最终接收是什么类型
// 4.验证是否是此类型 与 null
fun main() {
// 2.map int -> str 最终接收是什么类型
val p1 = KtBase89(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)
90、Kotlin语言的泛型类型约束
open class MyAnyClass(name: String) // 祖宗类 顶级父类
open class PersonClass(name: String) : MyAnyClass(name = name) // 父类
class StudentClass(name: String) : PersonClass(name = name) // 子类
class TeacherClass(name: String) : PersonClass(name = name) // 子类
class DogClass(name: String) // 其他类 另类
class CatClass(name: String) // 其他类 另类
// TODO 106-Kotlin语言的泛型类型约束学习
// T : PersonClass 相当于 Java的 T extends PersonClass
// 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("111")// 祖宗类 顶级父类
val per = PersonClass("222") // 父类
val stu = StudentClass("333") // 子类
val pea = TeacherClass("444") // 子类
val dog = DogClass("555") // 其他类 另类
/*val r1 = KtBase106(any).getObj() // 报错了,类型限定了
println(r1)*/
val r2 = KtBase106(per).getObj()
println(r2)
val r3 = KtBase106(stu).getObj()
println(r3)
val r4 = KtBase106(stu).getObj()
println(r4)
/*val r5 = KtBase106(dog).getObj() // 报错了,类型限定了
println(r5)*/
// KtBase106(CatClass("cat 小白")) // 报错了,类型限定了
}