Kotlin的解析(中)

前言

  經過上一篇的Kotlin介紹了一些基本的變量,方法,函數,類等的基本講解,接下來,讓咱們更近一步的學習,深刻一點的知識bash

1.  枚舉類和擴展

1.1 枚舉類

  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)
}
複製代碼
1.2 擴展

  擴展是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();//不須要實例,直接類名調用
//擴展範圍,放大
//在類中也可使用擴展
複製代碼

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以及其餘類擴充方法,比較靈活方便,也但願此篇幅的知識對你有稍許的幫助

相關文章
相關標籤/搜索