高级部分
抽象类主要作为多个类的模板,而接口则定义了多个类应该遵守的规范
拓展
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();
}
接口
- 修饰符可以是public | internal | private
- 一个接口可以有多个直接父接口,但接口只能继承接口,不能继承类
接口的属性要么声明为抽象属性,要么提供setter、getter方法
Kotlin接口成员可支持private和public两种访问权限
- 对于抽象方法、抽象属性必须使用public修饰,不加也默认public
- 对于不需要被实现类重写的成员,可以加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();
//必须实例化外部类之后才能实例化内部类
}