高級部分
抽象類主要作爲多個類的模板,而接口則定義了多個類應該遵守的規範
拓展
Kotlin的拓展是一個很獨特的功能(Java中是不存在的)
基類拓展的方法,子類對象也是可以使用的。 拓展方法的this和成員方法的this一樣是該對象的引用。
import java.util.*;
fun String.say() {
println("Hello MCM!");
}
fun main(args: Array<String>) {
var a : String = "Hello World!";
a.say();
}
還可以在fun後添加 <T> 聲明該函數是泛型函數
fun <T> ArrayList<T>.say() {
for (i in this.indices) {
println(this[i]);
println("Hello World");
}
}
fun main(args: Array<String>) {
var list: ArrayList<String> = ArrayList<String>();
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<String>) {
var base: BASE = EXTEND();
base.dynamic();
base.static();
}
拓展屬性
拓展屬性都是不能擁有幕後字段的,可以爲其提供自定義的幕後字段(private),或者使用計算字段
var <T> ArrayList<T>.last_index
get() = this.size - 1
set(value) {}
fun main(args: Array<String>) {
var arr: ArrayList<String> = ArrayList<String>()
arr.add("Hello");
arr.add("World");
arr.add("!");
println(arr.last_index); //Output: 2
}
以成員方式定義拓展
拓展的作用域只侷限於這個類中,在類外時訪問不到拓展的任何內容。
import java.util.*;
import kotlin.collections.ArrayList
class A
class B {
var a = A();
fun A.say() {
println("Hello World");
}
fun test() {
a.say();
}
}
fun main(args: Array<String>) {
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<String>) {
var b = B();
b.test();
}
帶接收者的匿名函數
使用匿名函數爲類拓展,該拓展函數所屬的類也是該函數的接收者。
這種匿名函數也稱作 “帶接收者的匿名函數”
只要省略拓展函數的名即可
open class A
class B : A()
fun main(args: Array<String>) {
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<String>) {
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<String>) {
SUB.HEAD().say();
}
內部類
內部類相當於非靜態成員,內部可以訪問到外部類的所有成員。但是要是想定義一個內部類成員,則必須要實例化一個外部類成員
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<String>) {
PERSON_STATIC.HEAD().say();
PERSON_INNER().HEAD().say(); //必須實例化外部類之後才能實例化內部類
}