在上一章節中,詳細的類(class)
作了一個實例講解,提到了類(class)
的實例化、構造函數、聲明、實現方式、和Java
中類的區別等。可是對於Kotlin
中的類的使用還遠遠不止那些。而且在上文中提到了關於類的類別。故而這篇文章就詳細說一說Kotlin
中的枚舉類(Enum
)、接口類(Interface
)的使用。
若是還對Kotlin
中的類尚未一個清晰的概念及認識的朋友請閱讀個人上一篇博文:html
- 關鍵字:
enum
- 枚舉常量:即枚舉類下的對象,每一個枚舉類包含0個到多個枚舉常量。
1.1.一、聲明github
enum
關鍵字在類頭中的class
關鍵字前面網絡
聲明格式:架構
enum class 類名{ ... }
1.1.二、枚舉常量less
枚舉類中的每個枚舉常量都是一個對象,而且他們之間用逗號分隔。ide
例:函數
/** * 例:關於一個網絡請求結果的枚舉類 */ enum class State{ /* NORMAL : 正常 NO_DATA : 數據爲空 NO_INTERNET : 網絡未鏈接 ERROR : 錯誤 OTHER : 其餘 */ NORMAL,NO_DATA,NO_INTERNET,ERROR,OTHER }
1.1.三、訪問枚舉常量源碼分析
- 不須要實例化枚舉類就能夠訪問枚舉常量
使用方式爲:性能
枚舉類名.枚舉常量.屬性
經過上面例子來實例講解:
// 使用中綴符號訪問枚舉常量 State.NORMAL.name State.NO_DATA.name State.NO_INTERNET.name State.ERROR.name State.OTHER.name
這裏只是讓你們明白怎樣去訪問一個枚舉常量。沒有講解到枚舉常量的使用。枚舉常量的使用請你們耐心的看下去。在下面會詳細介紹怎樣去使用它。
- 由於每個枚舉都是枚舉類的實例,因此他們能夠是初始化過的。
例:
enum class Color(var argb : Int){ RED(0xFF0000), WHITE(0xFFFFFF), BLACK(0x000000), GREEN(0x00FF00) }
- 要實現枚舉常量的匿名類,則必須提供一個抽象方法(必須重寫的方法)。且該方法定義在枚舉類內部。並且必須在枚舉變量的後面。
- 枚舉變量之間使用逗號(
,
)分割開。可是最後一個枚舉變量必須使用分號結束。否則定義不了抽象方法。- 在上面已經說過,每個枚舉常量就是一個對象。
例:
fun main(args: Array<String>) { ConsoleColor.BLACK.print() } enum class ConsoleColor(var argb : Int){ RED(0xFF0000){ override fun print() { println("我是枚舉常量 RED ") } }, WHITE(0xFFFFFF){ override fun print() { println("我是枚舉常量 WHITE ") } }, BLACK(0x000000){ override fun print() { println("我是枚舉常量 BLACK ") } }, GREEN(0x00FF00){ override fun print() { println("我是枚舉常量 GREEN ") } }; abstract fun print() }
輸出結果爲:
我是枚舉常量 BLACK
- 每一個枚舉常量都包含兩個屬性:
name(枚舉常量名)
和ordinal(枚舉常量位置)
- 提供了
values()
和valueOf()
方法來檢測指定的名稱與枚舉類中定義的任何枚舉常量是否匹配。- 自
Kotlin 1.1
起,可使用enumValues<T>()
和enumValueOf<T>()
函數以泛型的方式訪問枚舉類中的常量。
1.4.一、訪問枚舉變量屬性
例:
fun main(args: Array<String>) { println("name = " + Color.RED.name + "\tordinal = " + Color.RED.ordinal) println("name = " + Color.WHITE.name + "\tordinal = " + Color.WHITE.ordinal) println("name = " + Color.BLACK.name + "\tordinal = " + Color.BLACK.ordinal) println("name = " + Color.GREEN.name + "\tordinal = " + Color.GREEN.ordinal) } enum class Color(var argb : Int){ RED(0xFF0000), WHITE(0xFFFFFF), BLACK(0x000000), GREEN(0x00FF00) }
輸出結果爲:
name = RED ordinal = 0 name = WHITE ordinal = 1 name = BLACK ordinal = 2 name = GREEN ordinal = 3
1.4.二、使用enumValues<T>()
和 enumValueOf<T>()
訪問
例: 枚舉類仍是上面例子中的Color
類
println(enumValues<Color>().joinToString { it.name }) println(enumValueOf<Color>("RED"))
輸出結果爲:
RED, WHITE, BLACK, GREEN RED
1.4.三、使用valueOf()
和values()
檢測
例:
println(Color.valueOf("RED")) println(Color.values()[0]) println(Color.values()[1]) println(Color.values()[2]) println(Color.values()[3])
輸出結果爲:
RED RED WHITE BLACK GREEN
其中,若使用Color.valueOf("不存在的枚舉常量")
,則會拋出IllegalArgumentException
異常,即枚舉變量不存在。若使用Color.values()[大於枚舉常量位置]
,則會拋出下標越界異常。
即
Enum.kt
這個源文件。
在這裏我大體的說明一下這個源文件的方法、屬性等。有興趣的能夠去看看這個源文件。其實裏面也沒幾個方法。
1.5.一、默認實現了companion object {}
這也是咱們訪問枚舉常量無需實例化枚舉類的緣由。
1.5.二、僅提供了兩個屬性
- 即咱們上面用到的枚舉常量名稱(
name
)和枚舉常量位置(ordinal
)
貼上這兩個屬性的源碼:
/** * Returns the name of this enum constant, exactly as declared in its enum declaration. */ public final val name: String /** * Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial constant * is assigned an ordinal of zero). */ public final val ordinal: Int
1.5.三、實現了Comparable
接口
- 這也是咱們能獲取枚舉常量位置的緣由。
這是Enum.kt
源文件。讓你們看看它實現了Comparable
接口
public abstract class Enum<E : Enum<E>>(name: String, ordinal: Int): Comparable<E>{ ... }
再來看看Comparable.kt
裏面作了些什麼。其實裏面就提供了一個方法罷了...
public interface Comparable<in T> { /** * Compares this object with the specified object for order. Returns zero if this object is equal * to the specified [other] object, a negative number if it's less than [other], or a positive number * if it's greater than [other]. */ public operator fun compareTo(other: T): Int }
關於枚舉類的講解就寫到這裏了。不清楚的能夠多看看文章,或者看看源碼、官方文檔等等。固然,本身按照個人例子去敲一遍代碼也是很是不錯的。
2.1.一、聲明
關鍵字:
interface
定義格式:
interface 接口名{ ... }
2.1.二、用法
- 關鍵字:冒號(
:
),這一點是和Java
不一樣的。Java
中使用接口使用的是implements
關鍵字- 在
Kotlin
中冒號(:
)使用的地方不少:
- 用於變量的定義
- 用於繼承
- 用於接口
- 方法的返回類型聲明
使用格式:
class 類名 : 接口名{ // 重寫的接口函數、屬性等 ... }
2.1.三、舉例說明
fun main(args: Array<String>) { // 類的初始化 var demo = Demo1() demo.fun1() } /** * 我定義的接口 */ interface Demo1Interface{ // 定義的方法 fun fun1() } /** * 接口的實現類 */ class Demo1 : Demo1Interface{ override fun fun1() { println("我是接口中的fun1方法") } }
輸出結果爲:
我是接口中的fun1方法
- 不帶結構體的函數能夠省略大括號,且不用強制重寫帶結構體的函數就能夠直接調用。不太明白也不要緊,下面的代碼中都有註釋。
例:
fun main(args: Array<String>) { var demo = Demo2() demo.fun1() demo.fun2(5) println(demo.fun3(10)) println(demo.fun4()) //能夠不重寫該方法直接調用 demo.fun5() } interface Demo2Interface{ /** * 定義一個無參數無返回值的方法 */ fun fun1() /** * 定義一個有參數的方法 */ fun fun2(num: Int) /** * 定義一個有參數有返回值的方法 */ fun fun3(num: Int) : Int // 下面的兩個方法是有結構體, 故能夠不重寫 /** * 定義一個無參數有返回值的方法 */ fun fun4() : String{ return "fun4" } /** * 定義一個無結構體函數,大括號是能夠省略的 */ fun fun5(){ // 若是函數中不存在表達式,大括號能夠省略。 // 如fun1同樣 } } class Demo2 : Demo2Interface{ override fun fun1() { println("我是fun1()方法") } override fun fun2(num: Int) { println("我是fun2()方法,個人參數是$num") } override fun fun3(num: Int): Int { println("我是fun3()方法,個人參數是$num,而且返回一個Int類型的值") return num + 3 } override fun fun4(): String { println("我是fun4()方法,而且返回一個String類型的值") /* 接口中的fun4()方法默認返回」fun4「字符串. 能夠用super.fun4()返回默認值 也能夠不用super關鍵字,本身返回一個字符串 */ return super.fun4() } /* 接口中的fun5()帶有結構體,故而能夠不用重寫, fun4()一樣 */ // override fun fun5() { // super.fun5() // } }
輸出結果爲:
我是fun1()方法 我是fun2()方法,個人參數是5 我是fun3()方法,個人參數是10,而且返回一個Int類型的值 13 我是fun4()方法,而且返回一個String類型的值 fun4
- 在接口中申明屬性。接口中的屬性要麼是抽象的,要麼提供訪問器的實現。接口屬性不能夠有後備字段。並且訪問器不能夠引用它們。
2.3.一、做爲抽象
- 即重寫屬性的時候是在實現類的類參數中。這也是用代碼提示去重寫的實現方法
例:
fun main(args: Array<String>) { var demo = Demo3(1,2) println(demo.sum()) } interface Demo3Interface{ val num1: Int val num2 : Int } class Demo3(override val num1: Int, override val num2: Int) : Demo3Interface{ fun sum() : Int{ return num1 + num2 } }
輸出結果爲:
3
2.3.二、做爲訪問器
即手動方式去實現重寫,並提供get()方法
例:
fun main(args: Array<String>) { println(demo.result()) // 在這裏也能夠改變接口屬性的值 demo.num4 = 10 println(demo.result()) } interface Demo3Interface{ // 聲明比那倆和提供默認值 // 注意: val num3: Int = 3 這種方式不提供,爲直接報錯的 val num3: Int get() = 3 val num4: Int } class Demo3(override val num1: Int, override val num2: Int) : Demo3Interface{ // 提供訪問器實現 override val num3: Int get() = super.num3 // 手動賦值 override var num4: Int = 4 fun result() : Int{ return num3 + num4 } }
輸出結果爲:
7 13
- 該問題是指當咱們在父類中聲明瞭許多類型,有可能出現一個方法的多種實現。
例:
fun main(args: Array<String>) { // 類的初始化 val demo = Demo4() demo.fun1() demo.fun2() } interface Demo4InterfaceOne{ fun fun1(){ println("我是Demo4InterfaceOne中的fun1()") } fun fun2(){ println("我是Demo4InterfaceOne中的fun2()") } } interface Demo4InterfaceTwo{ fun fun1(){ println("我是Demo4InterfaceTwo中的fun1()") } fun fun2(){ println("我是Demo4InterfaceTwo中的fun2()") } } class Demo4 : Demo4InterfaceOne,Demo4InterfaceTwo{ override fun fun1() { super<Demo4InterfaceOne>.fun1() super<Demo4InterfaceTwo>.fun1() } override fun fun2() { super<Demo4InterfaceOne>.fun2() super<Demo4InterfaceTwo>.fun2() } }
說明:Demo4
實現了Demo4InterfaceOne
和Demo4InterfaceTwo
兩個接口,而兩個接口中都存在兩個相同方法名的方法。所以編譯器不知道應該選哪一個,故而咱們用super<接口名>.方法名
來區分。
我我的是從事Android
開發的,之前用Java
語言開發APP
時由於考慮到手機性能的問題幾乎用不到枚舉的。由於枚舉太消耗內存了。固然用Kotlin
語言開發Android
項目中是否要用到枚舉去便利去解決一些問題,此待小生本身研究。可是開發服務端項目時,一些問題用枚舉是很是便利性的。
對於接口類來講,它在一個項目中是重中之重的,對於項目中代碼的耦合性、便利性都能用接口類去實現一個良好的項目架構,對項目後期的維護或者說重構來講,都能有良好的體現。可能不少Java
開發者都深有體會
若是各位大佬看了以後感受還闊以,就請各位大佬隨便star
一下,您的關注是我最大的動力。
個人我的博客:Jetictors
個人掘金:Jetictors
Github:Jetictors