继承与重载的open关键字
KT所有的类,默认是final修饰的,不能被继承,和Java相反
open:移除final修饰类型转换
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())
}
// TODO 84.Kotlin语言的类型转换学习
// 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())
}
}
- 智能类型转换
open class Person3(val name: String) {
private fun showName() = "父类显示:$name"
open fun myPrintln() = println(showName())
fun methodPerson() = println("我是父类的方法...") // 父类独有的函数
}
class Student3(val nameSub: String) : Person3 (nameSub) {
override fun myPrintln() = println("子类显示:$nameSub")
fun methodStudent() = println("我是子类的方法...") // 子类独有的函数
}
fun main() {
val p : Person3 = Student3("李四")
(p as Student3).methodStudent()
p.methodStudent()
// 智能类型转换:会根据上面 as 转成的类型,自动明白,你现在的类型就是上面的类型
}
Any超类
所有的类都默认继承Any超类,等于Java的Object对象声明 object
对象表达式
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")
}
// 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")
}
}
- 伴生对象
// 伴生对象的由来: 在KT中是没有Java的这种static静态,伴生很大程度上和Java的这种static静态 差不多的
// 无论 KtBase89() 构建对象多少次,我们的伴生对象,只有一次加载
// 无论 KtBase89.showInfo() 调用多少次,我们的伴生对象,只有一次加载
// 伴生对象只会初始化一次
companion object {
val info = "UserInfo"
fun showInfo() = println("显示:$info")
val name = "Derry"
}
- 内部类 & 嵌套类
// 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")
}
}
}
// 默认情况下:就是嵌套类关系
// 嵌套类特点:外部的类 能访问 内部的嵌套类
// 内部的类 不能访问 外部类的成员
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()
}
- 数据类
// set get 构造函数 解构操作 copy toString hashCode equals 数据类 生成 更丰富
data class ResponseResultBean2(var msg: String, var code: Int, var data: String) : Any()
- copy
// 深拷贝 重新创建对象
data class User(val name: String)
val a = User("Alice")
val b = a.copy()
println(a === b) // 输出 false
//浅拷贝 复用同一个对象
data class Book(val title: String)
data class User(val name: String, val book: Book)
val u1 = User("Bob", Book("Kotlin"))
val u2 = u1.copy(name = "Alice")
u2.book.title = "Java" // 会同时修改u1.book
- 解构声明
// 普通类
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")
val(name1, age1, sex1) = Student2Data("李四", 89, '男')
println("数据类 结构后:name:$name1, age:$age1, sex:$sex1")
val(_, age2, _) = Student1("李四", 89, '男')
println("数据类 结构后: age2:$age2")
}
- 运算符重载
// 写一个数据类,就是为了,toString 打印方便而已哦
data class AddClass2(var number1: Int, var number2: Int) {
operator fun plus(p1: AddClass2) : Int {
return (number1 + p1.number1) + (number2 + p1.number2)
}
}
// TODO 94-Kotlin语言的运算符重载学习
fun main() {
// C++语言 +运算符重载就行了 -运算符重载就行了
// KT语言 plus代表+运算符重载
println(AddClass2(1, 1) + AddClass2(2, 2))
}
- 密封类
1. 替代枚举(Enum),但支持更灵活的数据类型
枚举的局限性:每个枚举值只能是单例,不能携带不同的数据。
密封类的优势:每个子类可以有自己的属性和方法,且可以是object(单例)或data class(带数据)。
sealed class PaymentMethod {
data class CreditCard(val cardNumber: String, val expiryDate: String) : PaymentMethod()
data class PayPal(val email: String) : PaymentMethod()
object Cash : PaymentMethod()
}
2. 结合 when 表达式,实现编译期安全检查
sealed class ApiResult {
data class Success(val data: String) : ApiResult()
data class Error(val message: String, val code: Int) : ApiResult()
}
fun handleResult(result: ApiResult) = when (result) {
is ApiResult.Success -> println("成功: ${result.data}")
is ApiResult.Error -> println("错误: ${result.message} (${result.code})")
// 不需要 else,编译器确保所有情况已覆盖
}
- 适用于状态管理(如 UI 状态、业务逻辑状态)
sealed class UiState {
object Loading : UiState()
data class Success(val data: List<String>) : UiState()
data class Error(val message: String) : UiState()
}
fun updateUI(state: UiState) = when (state) {
is UiState.Loading -> showProgressBar()
is UiState.Success -> showData(state.data)
is UiState.Error -> showError(state.message)
}
4. 替代 when + else 的防御性编程