1.概念
把類定義在其他類里面,定義在其他類內部的類即為嵌套類(或者寄生類),包含嵌套類的類稱為外部類(或者宿主類)。
根據定義的方式不一樣,又分為內部類、嵌套類、局部嵌套類。
內部類、嵌套類相當於外部類成員之一,可以使用public|internal|protected|private來修飾。
2.內部類
內部類相當於java沒有使用static修飾的內部類。使用inner關鍵字修飾。
(1)特點
- 內部類成員可以直接訪問外部類的私有數據,因為內部類相當於外部類的成員之一;
- 外部類不能訪問內部類的成員,如需訪問,需要通過創建內部類對象,通過對象訪問內部類成員。
(2)定義內部類
fun main(args: Array<String>) {
OuterClass().getInnerFunction()
}
/**
* 創建一個外部類
*/
class OuterClass {
//外部類的屬性可被內部類使用
private val outerParam = "外部類的私有屬性"
/**
* 外部類的私有方法可以被內部類調用
*/
private fun outerTest() {
println("外部類的私有方法")
}
/**
* 通過該類創建內部類對象,調用內部類方法
*/
fun getInnerFunction() {
// innerTest()//這種外部類直接調用內部類成員的方式是編譯不通過的,因為此時根本不存在內部類的對象
InnerClass().innerTest() //外部類想調用內部類,需定義一個內部類的對象,通過對象調用
}
/**
* 創建一個內部類
*/
inner class InnerClass {
//內部類成員,在外部類通過內部類的對象獲取,但是內部類可以直接調用外部類成員
fun innerTest() {
println("內部類的方法方法,外部類屬性:$outerParam")//獲取外部類屬性
outerTest()//調用外部類方法
}
}
}
(3)外部類-內部類交互原理
①為什么內部類可以調用外部類私有成員?
在內部類對象中,保存了一個該內部類所寄生的外部類的對象的引用。
內部類在方法中訪問屬性順序:方法是否有該變量(如果沒有,下同)=》內部類是否有該屬性=》外部類是否有該屬性,如果都沒有,則編譯報錯。
②為什么外部類不能直接調用內部類成員?
創建外部類對象時,內部類根本還不存在(如果沒有在外部類創建該內部類對象,(2)中的程序getInnerFunction()方法也是先創建了InnerClass對象才能調用InnerClass成員),因此也不存在直接使用該對象內部類的成員了。
3.嵌套類
嵌套類相當於java的靜態內部類(static class),但是kotlin完全取消了static關鍵字,所以kotlin類中除去嵌套類,其余成員均為非靜態成員。
內部類和嵌套類的使用考慮:優先考慮嵌套類。
(1)特點
- 嵌套類不能訪問外部類的其他成員,只能訪問其他嵌套類(參考java靜態內部類,靜態成員不能訪問非靜態成員);
- 跟內部類一樣,外部類不能直接調用嵌套類成員,如需調用,需創建嵌套類對象,通過對象調用嵌套類成員。
(2)定義嵌套類
fun main(args: Array<String>) {
OuterClass().outerTest()
}
/**
* 定義一個外部類
*/
class OuterClass {
val outerParam = "外部類屬性"
fun outerTest() {
// nestedTest()//不可以直接調用嵌套類成員
NestedClass().nestedTest()//可以通過創建嵌套類對象調用嵌套類成員
}
/**
* 定義一個嵌套類(相當於java靜態內部類)
*/
class NestedClass {
fun nestedTest() {
// println(outerParam)//此處是獲取不到外部類的屬性的
// outerTest()//此處是調用不了外部類的方法的
val nestClass2 = NestClass2()//可以訪問其他嵌套類
println("嵌套類方法")
}
}
/**
* 其他嵌套類
*/
class NestClass2
}
4.在外部類的外面使用內部類和嵌套類
(1)在外部類外部使用內部類(代碼接上)
fun main(args: Array<String>) {
//在外部類的外部使用內部類
val innerClass : OuterClass.InnerClass = OuterClass().InnerClass()
innerClass.innerTest()
}
(2)在外部類外部使用嵌套類(代碼接上)
fun main(args: Array<String>) {
//在外部類的外部使用外部類的嵌套類
val nestedClass: OuterClass.NestedClass = OuterClass.NestedClass()
nestedClass.nestedTest()
val nestClass2 : OuterClass.NestClass2 = OuterClass.NestClass2()
}
5.局部嵌套類(用得少)
把一個嵌套類放在方法或函數中定義,則這個嵌套類就是局部嵌套類。
(1)特點
- 作用域:只在方法內有效;
- 不能使用訪問權限修飾符(方法內變量均不允許);
- 很雞肋。
(2)定義局部嵌套類
fun main(args: Array<String>) {
OuterClass().localInnerTest()
}
/**
* 創建一個外部類
*/
class OuterClass {
/**
* 定義一個方法
*/
fun localInnerTest() {
/**
* 方法內定義一個局部嵌套類,可以被繼承
*/
open class LocalInnerClass {
/**
* 定義一個局部嵌套類的方法,可以被重寫
*/
open fun localInnerTest() {
println("LocalInnerClass")
}
}
/**
* 方法內定義另一個局部嵌套類,繼承於其他嵌套類
*/
class SubLocalInnerClass : LocalInnerClass() {
override fun localInnerTest() {
println("SubLocalInnerClass")
}
}
//只能在該方法內使用定義的局部嵌套類
val localInnerClass = LocalInnerClass()
localInnerClass.localInnerTest()
val subLocalInnerClass = SubLocalInnerClass()
subLocalInnerClass.localInnerTest()
}
}
