Kotlin基础学习记录
面向对象(下)
1.扩展
扩展方法 fun 被扩展类名().方法名()
open class Raw {
fun test() {
print("test方法")
}
}
class SubRaw : Raw() {
fun sub() {
print("sub方法")
}
}
fun Raw.info() {
print("===扩展的info方法===")
}
fun main() {
//扩展后Raw可以调用info;SubRaw也可以调用info
var t = Raw()
t.test()
t.info()
var s = SubRaw()
s.sub()
s.test()
s.info()
}
扩展的实现机制
本质上是定义了一个函数,当程序调用对象的扩展方法时,根据调用对象、方法名找到扩展函数,转换为函数调用
调用扩展方法由所在表达式的编译时类型决定
成员方法执行动态解析,扩展方法执行静态解析
成员方法优先级高于扩展方法
java调用扩展方法:
public void test(){
Raw raw = new Raw();
raw.test();
// raw.info(); 错误
RawKt.info(raw); //正确 文件名为Raw.kt,这里写为RawKt
}
可空类型的扩展方法
需要处理null值的情形
例:
//Raw.kt文件
fun Any?.ee(other:Any?):Boolean{
if (this==null)
return if (other==null) true else false
return this.equals(other)
}
//Java调用时
RawKt.ee("as",null)
扩展属性
扩展的属性只能是计算属性
- 不能有初始值(没有存储属性的幕后字段)
- 不能用field关键字显式访问幕后字段
- 扩展只读属性必须提供getter方法,读写属性提供setter、getter方法
示例:
//Raw.kt文件
class User1(var firstName:String, var lastName:String){}
var User1.fullName:String
get() = "${firstName}.${lastName}"
set(value) {firstName = value}
//Java调用时
User1 user = new User1("A","B");
RawKt.setFullName(user,"C");
System.out.println(RawKt.getFullName(user))
以成员方式定义扩展
以类成员的方式定义扩展(定义方法、属性的方式)
- 属于被扩展的类,可以直接调用被扩展类的成员(省略this)
- 位于定义它所在的类的类体中,可以直接调用所在类的成员(省略this)
class A {
var t = "A的属性t"
fun test() {
println("A的test方法")
}
}
class B {
var s = "B的属性s"
var t = "B的属性t"
fun test() {
println("B的test方法")
// var a = A()
// a.extension() //OK
}
fun A.extension() {
println("A的extension方法Start")
println(t)//A的属性t
println(this@B.t)//B的属性t
println(s)//B的属性s
println("A的extension方法End")
}
fun invokeMethod(target: A) {
test()//B的test方法
target.test()A的test方法
target.extension()
}
}
fun my() {
var b = B()
b.test()//B的test方法
b.invokeMethod(A())
// var a = A()
// a.extension()//ERROR
}
//output:
//B的test方法
//B的test方法
//A的test方法
//A的extension方法Start
//A的属性t
//B的属性t
//B的属性s
//A的extension方法End
总结:
- 扩展方法
A.extension()
可以直接调用被扩展类A
以及所在类B
的成员,若有冲突,被扩展类优先(A.extension
中的println(t)
输出为"A的属性t
"),若要执行所在类的成员可使用带标签的this进行限定(如:println(this@B.t)
) - 除
B
中可以调用a.extension()
方法,但外部的方法(包括A)似乎必须通过B
的invokeMethod()
才能访问extension
3. 目 前看来这个功能似乎有点繁琐,不知道有什么应用场景??
带接收者的匿名函数
支持为类扩展匿名函数
val f = fun A.(): Int {
return 6
}
//调用
A().f()
何时使用扩展
现阶段我还没什么感觉,可能以后再看会有一些感想吧
2.final和open修饰符
final:
- 默认final
- 修饰的类、属性、方法不可变
- 不可以修饰局部变量
疑问:属性不是由var|val决定了是否可变?
final表明能否被重写,在继承关系里,可变与不可变是另一个维度
可执行“宏替换”的常量
const修饰
final属性、final方法、final类
属性默认为final,方法默认为final
注意是重写还是重定义
类默认为final,不能被继承
3.抽象类
abstract修饰符
和Java类似
密封类
特殊的抽象类,其子类是固定的
密封类的子类必须与密封类在同一个文件中,间接子类无须在同一文件中
sealed class Apple {
abstract fun taste()
}
open class RedFuji : Apple() {
override fun taste() {
TODO("Not yet implemented")
}
}
4.接口
多继承
可以包含非抽象方法
不需要被重写的成员支持private
5.嵌套类和内部类
嵌套类:相当于静态内部类
内部类:非静态内部类
6.对象表达式和对象声明
object[:0~N个父类型]{
//对象表达式的类体部分
}
- 不能是抽象类
- 不能定义构造器(可以定义初始化块)
- 可以包含内部类,不能包含嵌套类
//TODO 待完成
7.枚举类
//TODO 待完成
8.类委托和属性委托
//TODO 待完成