Kotlin的解析(中)
通過上一篇的Kotlin介紹了一些基本的變數,方法,函式,類等的基本講解,接下來,讓我們更近一步的學習,深入一點的知識
1. 列舉類和擴充套件
1.1 列舉類
Kotlin的列舉類和Java的非常相似,具有類的特性,一般會將可列舉的同類型一組值作為列舉類定義,由於每一列舉都是個物件,可能在效能上還是不推薦用,Android中已經用註解慢慢取代了,這種列舉的使用
1.1.1 列舉類的基本用法
在kotlin中,列舉型別是以類的形式存在的,因此成為列舉類
enum class Direction { NORTH,SOUTH,WEST,EAST } 複製程式碼
1.1.2 列舉值指定對應的數值
從下面的程式碼可以看出,除了基本的語法不同,實現的規則和Java的非常相似
enum class Direction private constructor(val d:Int){ SOUTH(1),WEST(2); override fun toString(): String { return d.toString() } } fun main(args:Array<String>){ var dir1 : Direction = Direction. SOUTH var dir2= Direction. WEST println(dir1)//輸出的是1 println(dir2)//輸出的是2 } 複製程式碼
1.1.3 列舉的其他拓展
var dir1 : Direction = Direction. WEST Log.i("tag",dir1.name)//輸出的是:WEST Log.i("tag",dir1.ordinal.toString()) //輸出的是在列舉中的位置 1 Log.i("tag",dir1.toString()) //輸出的是傳入的數值 Log.i("tag",Direction.valueOf("WEST").toString()) //輸出的是傳入的數值 //如果要得到所有列舉的值,可以使用values的方法 for(d in Direction.values()){ println(d) } 複製程式碼
1.2 擴充套件
擴充套件是Kotlin中非常重要的功能,可以在沒有原始碼的情況下向類中新增成員,也可以啊子團隊開發的情況下,通過擴充套件,將模組分散給多個人開發
1.2.1 擴充套件原生API
Kotlin的原生的集合擴充套件
//這個方法放哪裡呢?一般都放在Kotlin檔案頂層,當然,也可以放在呼叫swap方法的位置前面 fun MutableList<Int>.swap(index1:Int ,index2:Int){ //為MutableList新增一個swap的方法,用於互動任意兩個集合元素的位置 var tmp = this[index1] this[index1] = this[index2] this[index2] = tmp; } val tab = mutableListOf(1,2,3) tab.swap(0,2) //原生裡面是沒有這個方法的,通過擴充套件就可以了,牛逼 Log.i("tag","jihe:" + tab.toString())//輸出[3,2,1] 複製程式碼
JDK標準的集合類ArrayList添加了一個hellow的方法
fun ArrayList<Int>.hellow(string: String){ println(string) } var list: ArrayList<Int> = ArrayList(); list.add(20) list.add(30) list.add(40) list.add(50) list.swap(0,2)//這個是原生自帶的 list.hellow("牛逼吧!!!嘻嘻") //這個是上面自己寫的一個方法 複製程式碼
1.2.2 擴充套件自定義類
擴充套件類的目的很多,除了系統類需要擴充套件之外,我們自己編寫的類有時候也需要擴充套件,但是我們有不想去類裡面修改,這時候這個功能就相得益彰
open class Parent(val va1: Int, val va2: Int) {//使用open宣告,才能允許其他類繼承 var mVal1 = va1 var mVal2 = va2 fun add() = this.mVal1 + this.mVal2 } class Child(va1: Int, va2: Int) : Parent(va1, va2) { fun sub() = mVal1 - mVal2 } fun Parent.log() { Log.i("tag", "父類:" + "${mVal1} +${mVal2} = ${add()}") } fun Child.log() { Log.i("tag", "子類:" + "${mVal1} -${mVal2} = ${sub()}") } var par1: Parent = Parent(1, 2) var par2: Parent = Child(1, 2) var chil1: Child = Child(1, 2) par1.log()//父類:1 +2 = 3 par2.log()//父類:1 +2 = 3 chil1.log()//子類:1 -2 = -1 open class Parent(val va1: Int, val va2: Int) { var mVal1 = va1 var mVal2 = va2 fun add() = this.mVal1 + this.mVal2 //內部成員函式,和擴充套件同名,擴充套件覆蓋不了內部 fun log() { Log.i("tag", "父類:自己" + "${mVal1} +${mVal2} = ${add()}") } } fun Parent.log() { Log.i("tag", "父類:" + "${mVal1} +${mVal2} = ${add()}") } fun Child.log() { Log.i("tag", "子類:" + "${mVal1} -${mVal2} = ${sub()}") } var par1: Parent = Parent(1, 2) var par2: Parent = Child(1, 2) var chil1: Child = Child(1, 2) par1.log()//父類:自己1 +2 = 3 par2.log()//父類:自己1 +2 = 3 chil1.log()//父類:自己1 +2 = 3 複製程式碼
上面可以看出:(1)儘管par2的例項物件是Child,但是通過擴充套件的方法,並沒有重寫父類的擴充套件方法,因此par2呼叫的還是父類的方法。 (2)類內部成員函式和通過擴充套件新增的成員函式衝突,那麼內部成員函式的優先順序更高,通過擴充套件無法覆蓋內部成員函式
1.2.3 擴充套件伴隨物件
如果類中有伴隨物件(由於Kotlin類不支援靜態成員變數,因此引入了伴隨物件,來解決類沒有靜態成員所帶來的尷尬),那麼可以利用擴充套件物件新增成員
class SubClass{ companion object { } } funSubClass.Companion.nihao(){ Log.i("tag","hello word!") } SubClass.nihao();//不需要例項,直接類名呼叫 //擴充套件範圍,放大 //在類中也可以使用擴充套件 複製程式碼
2. 資料類和封裝
資料類和封裝是Kotlin中兩種特殊的類,前者用於描述資料和相應的操作,後者相當於列舉類的擴充套件,用於描述有限的資料 #####2.1 資料類 資料類是Kotlin 的一個語法糖,Kotlin編譯器會自動為資料類生產一些成員函式,以提高開發效率
2.1.1 使用資料類
//一般的類的書寫 class User(var name: String, var sex: Int){ var mName = name var mSex = sex override fun equals(other: Any?): Boolean { //重寫,是不是感覺的很不爽,要寫這麼多 if (other is User) { if (mName == other.mName && mSex == other.mSex) { return true } } else { return false } return false } override fun toString(): String { //重寫,是不是Java中很煩,yes,很煩 return "User {name = $mName \n sex = $mSex }" } } 複製程式碼
從上面User可以看出,只有name和sex是必要的,其餘的都可以自動的推倒,而怎麼弄呢?其實Kotlin中提供了,那就是在class前面加上data關鍵字就行了
data class Student(var name: String) { constructor():this("sdfdf")//為了新增一個無參的建構函式 } var student = Student("xixi") var student1 = Student("haha") Log.i("tag", student.toString()); //輸出:Student(name=xixi) Log.i("tag", student1.toString());//輸出: Student(name=haha) Log.i("tag", student.equals(student1).toString());//輸出:false 複製程式碼
資料類和普通的類最大的不同,就是資料類可以根據構造器的引數自動生成相關的程式碼;如果Kotlin中,同事具有普通類,以及儲存和管理資料的功能,建議直接使用資料類
編寫資料類注意事項
(1)主構造器至少有一引數
(2)主構造器的引數必須標記為var/val
(3)資料類不能是抽象類,open類,封閉類(sealed)類或內部類(inner) 由於主構造器必須要有一個引數,不可能存在沒有引數的主構造器,要想擁有,兩種方案解決:
(1)為主構造器每個引數都加上預設值
data class User(val name :String="Bill", var age :Int = 10) 複製程式碼
(2)新增一個沒有引數的構造器,呼叫主構造器時,指定預設引數
data class User(var name : String ,var age :Int){ //次建構函式 constructor():this("Devin","18") } 複製程式碼
2.1.2 資料類成員的解構
資料類成員解構,這裡關鍵解構,也就是解除結構,在資料類中,用屬性表示資料,這些屬性屬於同一資料類,要想使用這些屬性,必須首先引用資料物件,這裡的解構就是指將這些資料物件的屬性提取出來,分別單獨賦值給變數
var student = Student("大家好") val (name) = student Log.i("tag", ";;;;;;"+name );//;;;;;;大家好 複製程式碼
2.1.3 封閉類
封閉類也是Kotlin的一個語法糖,可以把它理解為列舉的擴充套件,一個封閉類,前面用sealed,可以有任意多個字物件,封閉類的值只能是這些字物件,使用封閉類的好處,主要是與when表示式配合,不需要再使用else形式
sealed class Icon () class Small() : Icon() class Big() : Icon() fun eval(icon: Icon) { when (icon) { is Small -> { } is Big -> { } } } var big = Big() eval(big) 複製程式碼
3. 泛型
3.1 泛型基礎
所謂的泛型,就是指在定義資料結構時,只指定型別的佔位符,等到使用該資料結構時在指定具體的資料型別
class Box<T>(t :T){ var value = t } var box = Box<Int>(1) Log.i("tag", ";;;;;;" + box.value); 複製程式碼
3.2 型別變異
Kotlin泛型並沒有提供萬用字元,取而代之的是out和in的關鍵字(1)用out宣告的泛型佔位符只能用在獲取泛型型別值的地方(2)用in宣告的泛型只能在設定泛型型別值的地方
(1). 使用out關鍵字
abstract class Source< out T> { abstract fun NextT(): T } fun demo(strs: Source<String>) { //編譯通過,因為T是一個out型別引數 val ni: Source<Any> = strs } 複製程式碼
(1).使用in關鍵字
abstract class Comparable<in T>{ abstract fun comparaTo(other:T) } fun demo (x:Comparable<Number>){ //1.0時Double型別,Double時Number的子型別 x.comparaTo(1.0) val y: Comparable<Double> = x } 複製程式碼
3.3 泛型函式
fun <T> single(item :T) :T{ return item } var single = single(1) Log.i("tag", ";;;;;;" + single); 複製程式碼
3.4 泛型約束
最常見的約束是上界(upper bound),與Java的extends關鍵字相同,如果沒有指定,預設使用的上界型別Any?,在定義泛型引數的尖括號內,只允許定義唯一一個上界,要是多個就的使用where
fun <T :Parent> convert(item :T){ } fun<T>clone (list:List<T>,there:T):List<T> where T :Comparable,T:Cloneable{ //..... } 複製程式碼
總結
通過本章節的學習,瞭解到了列舉類,資料類,封閉類,泛型,而且學到了非常方便的一個擴充套件的實用語法,可以很方便的為原生Api以及其他類擴充方法,比較靈活方便,也希望此篇幅的知識對你有稍許的幫助