經過上一篇的Kotlin介紹了一些基本的變量,方法,函數,類等的基本講解,接下來,讓咱們更近一步的學習,深刻一點的知識bash
Kotlin的枚舉類和Java的很是類似,具備類的特性,通常會將可枚舉的同類型一組值做爲枚舉類定義,因爲每一枚舉都是個對象,可能在性能上仍是不推薦用,Android中已經用註解慢慢取代了,這種枚舉的使用數據結構
1.1.1 枚舉類的基本用法ide
在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 枚舉的其餘拓展ui
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)
}
複製代碼
擴展是Kotlin中很是重要的功能,能夠在沒有源代碼的狀況下向類中添加成員,也能夠啊子團隊開發的狀況下,經過擴展,將模塊分散給多我的開發this
1.2.1 擴展原生APIspa
Kotlin的原生的集合擴展code
//這個方法放哪裏呢?通常都放在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 {
}
}
fun SubClass.Companion.nihao(){
Log.i("tag","hello word!")
}
SubClass.nihao();//不須要實例,直接類名調用
//擴展範圍,放大
//在類中也可使用擴展
複製代碼
數據類和封裝是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)
複製代碼
所謂的泛型,就是指在定義數據結構時,只指定類型的佔位符,等到使用該數據結構時在指定具體的數據類型
class Box<T>(t :T){
var value = t
}
var box = Box<Int>(1)
Log.i("tag", ";;;;;;" + box.value);
複製代碼
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
}
複製代碼
fun <T> single(item :T) :T{
return item
}
var single = single(1)
Log.i("tag", ";;;;;;" + single);
複製代碼
最多見的約束是上界(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以及其餘類擴充方法,比較靈活方便,也但願此篇幅的知識對你有稍許的幫助