Kotlin高阶面向对象

高级部分
抽象类主要作为多个类的模板,而接口则定义了多个类应该遵守的规范
拓展
Kotlin的拓展是一个很独特的功能(Java中是不存在的)
基类拓展的方法,子类对象也是可以使用的。 拓展方法的this和成员方法的this一样是该对象的引用。

import java.util.*; fun String.say() { println("Hello MCM!"); } fun main(args: Array>) { var a : String = "Hello World!"; a.say(); }

还可以在fun后添加 声明该函数是泛型函数
fun ArrayList.say() { for (i in this.indices) { println(this[i]); println("Hello World"); } } fun main(args: Array>) { var list: ArrayList> = ArrayList>(); list.add("A"); list.add("B"); list.add("C"); list.say(); }

拓展的实现机制 Java是静态语言,一个类被定义完成无法动态添加和删除成员,除非重新编译该类
成员方法执行动态解析(由运行时类型决定)
拓展方法执行静态解析(由编译时类型决定)
open class BASE { open fun dynamic(){ println("BASE_DY"); } } class EXTEND : BASE(){ override fun dynamic() { println("EXTEND_DY"); } } fun BASE.static() { println("BASE_ST"); } fun EXTEND.static() { println("EXTEND_ST"); } fun main(args: Array>) { var base: BASE = EXTEND(); base.dynamic(); base.static(); }

拓展属性 拓展属性都是不能拥有幕后字段的,可以为其提供自定义的幕后字段(private),或者使用计算字段
var ArrayList.last_index get() = this.size - 1 set(value) {} fun main(args: Array>) { var arr: ArrayList> = ArrayList>() arr.add("Hello"); arr.add("World"); arr.add("!"); println(arr.last_index); //Output: 2 }

以成员方式定义拓展 拓展的作用域只局限于这个类中,在类外时访问不到拓展的任何内容。
import java.util.*; import kotlin.collections.ArrayListclass A class B { var a = A(); fun A.say() { println("Hello World"); } fun test() { a.say(); } } fun main(args: Array>) { var b = B(); b.test(); // b.a.say(); 会报错,因为拓展的作用域只在B类中 }

若在拓展的函数中使用的方法在 本类和被拓展的类中重名,参数列表也一样 返回值也一样的情况下,会优先使用被拓展类中的那个方法,除非使用 this@当前类名.方法 这种形式才能使用本类的方法。
之所以使用这种方式是因为默认的this是被拓展类对象的引用,通过 this@当前类名 这种方式可以临时将this作为当前类对象引用
class A { fun hello() { println("Hello A!"); } } class B { fun hello() { println("Hello B!"); }var a = A(); fun A.say() { hello(); this@B.hello(); } fun test() { a.say(); } } fun main(args: Array>) { var b = B(); b.test(); }

带接收者的匿名函数 使用匿名函数为类拓展,该拓展函数所属的类也是该函数的接收者。
这种匿名函数也称作 “带接收者的匿名函数”
只要省略拓展函数的名即可
open class A class B : A() fun main(args: Array>) { var b = B(); var hello = fun A.() { println("Hello"); } b.hello(); var say : A.() -> Unit; say = {println("Say")} b.say(); }

也可以使用Lambda表达式来拓展属性,这种函数类型为 拓展类名.函数类型
抽象
包含抽象成员的类只能被定义成抽象类,抽象类种可以没有抽象成员
抽象类不能被实例化,即使这个抽象类中没有抽象成员
与Java类似,Kotlin也允许抽象成员重写非抽象成员
open class BASE { open fun say(){ println("Hello World"); } } abstract class SUB: BASE(){ override abstract fun say(); }

接口
  1. 修饰符可以是public | internal | private
  2. 一个接口可以有多个直接父接口,但接口只能继承接口,不能继承类
接口可以包含抽象方法也可包含非抽象方法,但接口中的属性没有幕后字段。
接口的属性要么声明为抽象属性,要么提供setter、getter方法
Kotlin接口成员可支持private和public两种访问权限
  1. 对于抽象方法、抽象属性必须使用public修饰,不加也默认public
  2. 对于不需要被实现类重写的成员,可以加private修饰,将这些成员在接口内访问。
接口的继承 接口完全支持多继承
虽然不能实例化,但可用来声明变量。必须引用到具体的实现类。
嵌套类与内部类
嵌套类(默认) ? 嵌套类相当于静态内部类,由于Kotlin取消了static修饰符,因此都是非静态成员。因此嵌套类不可访问外部类的其他任何成员(只能访问其他嵌套类)
class PERSON { var x = 1; class HEAD { fun say() { println(x); //嵌套类(静态内部类),访问不到x } } } fun main(args: Array>) { var PH = PERSON.HEAD(); PH.say(); }

嵌套类相当于外部类的静态成员,因此外部类的所有方法、属性、 初始化块都可以使用嵌套类来定义变量、创建对象。
子类无法使用父类的内部类
open class PERSON_STATIC { class HEAD { fun say() { println("STATIC CLASS"); } } }class SUB: PERSON_STATIC() fun main(args: Array>) { SUB.HEAD().say(); }

内部类 【Kotlin高阶面向对象】? 内部类相当于非静态成员,内部可以访问到外部类的所有成员。但是要是想定义一个内部类成员,则必须要实例化一个外部类成员
class PERSON_STATIC { class HEAD { fun say() { println("STATIC CLASS"); } }}class PERSON_INNER { inner class HEAD { fun say() { println("INNER CLASS"); } }} fun main(args: Array>) { PERSON_STATIC.HEAD().say(); PERSON_INNER().HEAD().say(); //必须实例化外部类之后才能实例化内部类 }

    推荐阅读