示例来自bilibili Kotlin语言深入解析 张龙老师的视频
基础部分
Kotlin学习笔记 第一章开始 第二章 基础_积跬步 至千里-CSDN博客
类与继承
Kotlin学习笔记 第二章 类与对象 第一节类与继承(补)_积跬步 至千里-CSDN博客
属性
Kotlin学习笔记 第二章 类与对象 第二节属性_积跬步 至千里-CSDN博客
接口
Kotlin学习笔记 第二章 类与对象 第三节接口 第四节 函数式接口_积跬步 至千里-CSDN博客
可见性 扩展属性与方法
Kotlin学习笔记 第二章 类与对象 第五节 可见性 第六节 扩展_积跬步 至千里-CSDN博客
部分重点
if可以作为表达式
when表达式
in 关键字
主构造函数 次构造函数 什么情况constructor关键字可以省略
补充: 在JVM上 如果主构造方法的所有参数都有默认值 那么Kotlin编译器会为这个类生成无参构造方法,这个无参的构造方法会使用这些默认值。这样做可以与String框架更好的兼容
init 代码块 init块执行的顺序与它所在的位置有关
string模板
Kotlin中所有类默认是final的 final与open相反 想要扩展一个类 需要加上open关键字
补充:1.在Kotlin中如果有主构造函数 次构造函数必须通过this关键字调用主构造方法 或者通过this关键字调用其他次构造方法再间接调用主构造方法
补充:2.如果一个类继承了另外一个类 且没有主构造方法 那么这个类的次构造方法必须用super关键直接或通过其他次构造方法间接调用父类的构造方法
class SingleClass(name: String) {
constructor(name: String, age: Int) : this(name)
constructor(name: String, age: Int, address: String) : this(name, age)
}
class SingleClass2() {
constructor(name: String, age: Int) : this()
constructor(name: String, age: Int, address: String) : this(name, age)
}
open class Parent2 {
constructor(name: String)
}
class Child1(name: String) : Parent2(name) {
}
class Child2 : Parent2 {
// 直接调用
constructor(name: String) : super(name)
// 间接调用
constructor(name: String, age: Int) : this(name)
}
val 可以覆盖val
var可以覆盖var和val
val不能覆盖var
对象声明 object xx 对象声明其实是一个饿汉式单例
Kotlin中的静态方法:定义在顶层空间即可
伴生对象
伴生对象如果没有定义名字 它的会有一个默认名字 Companion
补充:
伴生对象内部会生成一个静态内部类
伴生对象的属性和方法看起来像静态成员 但是在运行期 他们依旧是真实对象的实例成员 想要将他们变成真正的静态方法与属性 可以通过加上 @JvmStatic 注解实现 加上这个注解
幕后字段field
lateinit:
Kotlin规定非空类型属性必须在构造函数中初始化 如果不想这么做 可以使用延迟初始化
lateinit使用前提
1.lateinit不能用在主构造方法的属性上
2.lateinit修饰的属性不能有自定义get set方法
3.属性类型需要为非空 且不能是原生数据类型
可见性 private protected internal public
扩展属性与扩展方法
扩展函数的解析是静态的
1.扩展本身不会真正修改目标类(它不会真的插入属性或方法 而是在调用时将当前对象作为第一个参数传递进去 然后调用方法或者属性)
2.扩展函数的解析是静态的 它不是动态的 不支持多态 调用取决于声明类型
3.调用由对象声明类型决定 而不是实际类型
open class AA
class BB : AA()
fun AA.a() = "a"
fun BB.a() = "b"
fun myPrint(aa: AA) {
println(aa.a())
}
fun main() {
myPrint(AA())
// 扩展函数的解析是静态的 不支持多态 调用由对象声明类型决定
myPrint(BB())
}
class D03Add2 {
}
可以对可空类型进行扩展
class CC {
fun foo() {
println("member")
}
}
fun CC.foo() {
println("member2")
}
fun CC.foo(string: String) {
println("member2 $string")
}
fun main() {
// 扩展方法名字与成员方法名字冲突 成员方法优先
CC().foo()
// 扩展方法支持重载
CC().foo("aa")
}
扩展作用域
1.扩展函数所定义的类的实例叫分发接收者(dispatch receiver)
2.扩展函数所扩展的那个类的实例叫做扩展接收者(extension receiver)
3.当两个名字冲突时 扩展接收者优先级更高
// DD的实例代扩展接收者
// 扩展函数所扩展的那个类的实例叫做扩展接收者
class DD{
fun method(){
println("Do method")
}
}
// EE的实例代表分发接收者
// 扩展函数所定义的类(EE)的实例 做扩展接收者(extension receiver)
class EE {
fun method2(){
}
// DD 的扩展方法可以调用分发接收者的方法 也可以调用扩展接收者的方法
fun DD.hello(){
method()
}
fun DD.output1(){
// 当扩展接收者和分发接收者 两个名字冲突时 扩展接收者优先级更高
println(toString())
}
fun DD.output2(){
// 当扩展接收者和分发接收者 两个名字冲突时 扩展接收者优先级更高 但是可以用this@EE 绕过这一限制
println(this@EE.toString())
}
fun test(){
val dd = DD()
dd.output1()
dd.output2()
}
}
fun main() {
var dd = DD()
// dd.hello() // 调用失败 扩展分发如果在非顶层空间定义 其有效范围只在其定义的类中有效
EE().test()
}
// 扩展可以很好解决Java类中各种辅助类过多的情况
class D03Add4 {
}
函数式接口
只有一个方法的接口 可以用lambda表达式替换
========================================
数据类
Kotlin学习笔记 第二章 类与对象 第七节 数据类_积跬步 至千里-CSDN博客
枚举类 密封类
Kotlin学习笔记 第二章 类与对象 第十一节 枚举类 第八节密封类_积跬步 至千里-CSDN博客
泛型
Kotlin学习笔记 第二章 类与对象 第九节 泛型_积跬步 至千里-CSDN博客
内部类嵌套类
Kotlin学习笔记 第二章 类与对象 第十节 内部类嵌套类_积跬步 至千里-CSDN博客
对象表达式与对象声明 类型别名
Kotlin学习笔记 第二章 类与对象 第十二 十三节 对象表达式与对象声明 类型别名_积跬步 至千里-CSDN博客
委托
Kotlin学习笔记 第二章 类与对象 第十四 十五节 委托 委托属性_积跬步 至千里-CSDN博客
数据类
解构声明
密封类 密封类从某种角度上看是枚举类的升级版
泛型 协变 逆变 不变 星投影 类型投影
嵌套类 嵌套类无法访问外部类的属性和方法
内部类
内部类 vs 嵌套类 内部类使用inner关键字修饰 内部类有一个外部类的引用 因此内部类可以在类体中访问外部类的属性和方法 嵌套类不行
内部类访问外部类方法 this@Outer2.test() // 调用外部类的方法
对象表达式格式为 object [:若干父类型, 中间用都会分隔]{
}
匿名对象
匿名对象只能在局部变量范围内或是被private修饰的成员变量范围内才能被识别出真正的类型
如果将一个匿名对象当作public方法的返回类型或是public属性的类型 那么改方法/属性的真正类型就是这个匿名对象所声明的父类型,如果他没有声明父类型 那么其类型是Any
这种情况下 匿名对象中所声明的任何成员都是无法访问的
枚举
对象表达式 vs 对象声明
1.对象表达式时立刻初始化或执行的
2.对象声明是延时初始化的 首次访问才会初始化
3.伴生对象是在其所对应的类被加载时初始化的 对应Java的静态初始化
4.对象声明 : object单独使用
5.对象表达式 :object 对象作为参数或者被用于赋值 例如匿名内部类
委托
属性委托的原理
对于每个委托属性来说 Kotlin编译器会在底层生成一个对应的辅助属性,将所有对原属性的操作 都转交为对该辅助属性的操作
例如 有委托属性prop Kotlin编译器会在底层生成一个对应的辅助属性prop$delegate 所有对prop的操作(包括读写) 都会委托给
这个由kotlin编译器生成的额外的辅助属性
属性委托分类
1 延迟属性 Lazy
2 非空属性
3 可观测属性
4 map 属性委托
接口委托的原理
by关键字后面的类 实际上会有一个对象实例存储在委托类内部 编译器会将当前类的所有方法实现出来, 在实现内部调用委托对象的实例的对应方法
可读可写的属性的委托:
可以选择实现ReadWriteProperty的两个方法 也可以自己写这两个方法
提供委托



