Kotlin基礎(chǔ)全教程

Android為啥要從Java轉(zhuǎn)向Kotlin

Kotlin 是一種在 Java 虛擬機(jī)上運(yùn)行的靜態(tài)類型編程語(yǔ)言弓候,被稱之為 Android 世界的Swift晒哄,由 JetBrains 設(shè)計(jì)開(kāi)發(fā)并開(kāi)源当编。蘋(píng)果公司已經(jīng)在用Swift語(yǔ)言替代Object-C語(yǔ)言,Google也找到了替代Java的語(yǔ)言,也就是JetBrains公司(Android Studio也是用該公司的Intelli J改的)主推的Kotlin。現(xiàn)在將kotlin作為了編寫(xiě)Android的官方語(yǔ)言欢摄,而后會(huì)有越來(lái)越多的項(xiàng)目使用Kotlin。Kotlin有了強(qiáng)有力的親爸JetBrains公司和Google這個(gè)干爸笋粟,自然被捧在手心了怀挠。

Kotlin在編寫(xiě)代碼時(shí)有如下優(yōu)勢(shì):

  • 代碼簡(jiǎn)潔高效
  • Android Jetpack 與其他庫(kù)中的 Kotlin 支持
  • 可與 Java 的一起使用
  • 空指針安全

同樣,kotlin支持函數(shù)式編程害捕、支持lambda表達(dá)式绿淋、流式API...,此處略去一萬(wàn)字尝盼」總之,Java是上世紀(jì)的編程語(yǔ)言了东涡,當(dāng)你學(xué)過(guò)了Kotlin之后 ,你會(huì)發(fā)現(xiàn)倘待,之前寫(xiě)過(guò)那么多的代碼都是在浪費(fèi)生命疮跑。

語(yǔ)法基礎(chǔ)

變量
    var age: Int = 0
    var num = 20
    val TYPE: Int = 100  
    var name: String = ""  

寫(xiě)法形如:var str: String
用var或val聲明,前面是參數(shù)名凸舵,后面是參數(shù)的類型祖娘,中間用:分割

var即英文“variable”的意思,聲明成一個(gè)可變變量。val即英文“value”的意思渐苏,申明的是一個(gè)不可變變量掀潮,對(duì)應(yīng)的java里面的final。

kotlin中有優(yōu)秀的類推導(dǎo)機(jī)制琼富,age聲明了變量類型仪吧,num沒(méi)有聲明變量類型,但是依然可以通過(guò)鞠眉,是由Kotlin自動(dòng)推導(dǎo)了類型薯鼠。

常量

const
如果只讀屬性的值在編譯期是已知的,那么可以使用 const 修飾符將其標(biāo)記為編譯期常量械蹋,相當(dāng)于java中的public static final修飾出皇。

    //const val 需與 companion object 搭配使用
    companion object {
        const val VERSION = 1
    }
空指針檢查

在Kotlin里,可以用“?”表示可以為空哗戈,也可以用“!!”表示不可以為空郊艘。
給變量加上?標(biāo)識(shí),會(huì)通告所有使用該變量的地方唯咬,必須給出為空的補(bǔ)救措施纱注。

     var info: String? = null

        println(info?.length)  //第一種補(bǔ)救:如果info為null,就不執(zhí)行后面的.length代碼

        println(info!!.length)  //第二種補(bǔ)救:這里如果為null副渴,我自己負(fù)責(zé)info奈附,會(huì)報(bào)出空指針,這種處理需慎用

        if (info != null) {   //第三種補(bǔ)救措施煮剧,如下這種同java寫(xiě)法
            println(info.length)
        }

      println(info?.length ?: "空數(shù)據(jù)")  //第四種補(bǔ)救措施斥滤,如果真的為null,則改為返回"空數(shù)據(jù)"

第二個(gè)檢查方式是let函數(shù)勉盅,?.當(dāng)然能解決大部分問(wèn)題佑颇,但是user每使用一次?.相當(dāng)于都加上了代碼if(user != null),實(shí)際上在同一個(gè)函數(shù)中草娜,我們只需要做一次非空判斷就行了挑胸,這就是我們的let函數(shù)的作用,在代碼塊內(nèi)容用it代替該對(duì)象宰闰。

user?.let {
            it.login()
            it.logout()
        }
可見(jiàn)性修飾符

在 Kotlin 中有這四個(gè)可見(jiàn)性修飾符:private茬贵、 protected、 internal 和 public移袍。 如果沒(méi)有顯式指定修飾符的話解藻,默認(rèn)可見(jiàn)性是 public。
internal:在本模塊內(nèi)可見(jiàn)

字符串拼接

將變量拼接在字符串之內(nèi)葡盗,用${}來(lái)包裹變量即可

    fun StringFormat(title: String) = {
        "這里是拼接字符串${title}"
    }

字符串自動(dòng)換行:

val content = """
            哈哈哈哈
            呵呵呵呵
            嘿嘿嘿嘿
        """.trimIndent()
值比較螟左、賦值:
        println(name1.equals(name2))  //同java的equals

        println(name1 == name2)  //同equals作用,比較值的相等,這里為true

        println(name1 === name2)  //比較地址是否相等胶背,即比較是否為同一個(gè)對(duì)象巷嚣,這里為false

    val name1 = "lili"
    val name2 = "lili"
    println(name1 === name2) //這里返回ture,因?yàn)樽址诔A砍厥菑?fù)用一份的

將條件判斷的結(jié)果賦值:

        val num1 = 100
        val num2 = 101
        val max = if (num1 > num2) num1 else num2
when

用when關(guān)鍵字代替java中的switch使用钳吟,when作為判斷廷粒,條件可為任意類型

fun whenUse(obj: Any, type: Int) {
        when(obj) {
            1 ->
                ""
            in 2..5 ->
                ""
            is String ->
                ""
            else ->
                ""
        }
    }

val week = 5
        val info = when(week) {
            1 -> "星期一"
            1 -> "星期二"
            3 -> println()
            4 -> 5
            -1 -> TODO()  //Nothing類型:表示未實(shí)現(xiàn)的功能,會(huì)拋出異常 public inline fun TODO(): Nothing = throw NotImplementedError()
            else -> ""  //返回String類型砸抛,info一定是String類型
        }

//將when的返回值直接使用起來(lái)賦值:
        val info2 = when(week) {
            1 -> "星期一"
            2 -> "星期二"
            3 -> println()
            4 -> true
            in 2..5 ->
                ""
            else -> {  //必須要有else
                //else 返回括號(hào)评雌,info2就可以是任意類型 Any
            }
        }
Any

java中所有類的父類是Object,而Kotlin中所有類的父類為Any直焙。

object

Kotlin中沒(méi)有大寫(xiě)的Object了景东,而是有小寫(xiě)的object,表示單例奔誓。

class SingleTon {
    object Holder {
        var instance = SingleTon()
    }
}
is

Kotlin中用is代碼java中的instanceOf 來(lái)判斷類型

 fun charge() {
        var type = ""
        if (type is String) {  //instanceOf

        }
    }
in使用
  • in來(lái)檢查一個(gè)值是否在一個(gè)區(qū)間內(nèi)
fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z'   //檢查字符是否為字母
  • 檢查list中是否有元素name
    fun inList() {
        val names = listOf("lala", "haha", "yaya")
        if("lili" in names) {

        }
    }
takeIf斤吐,takeUnless函數(shù)
        user.name.takeIf {
            TextUtils.isEmpty(it)
        }.let {
            print(it)
        }

        user.name.takeUnless {
            !TextUtils.isEmpty(it)
        }.let {
            print(it)
        }

takeIf的閉包返回一個(gè)判斷結(jié)果,如果為false時(shí)takeIf函數(shù)返回null厨喂;takeUnless與takeIf相反和措,為true時(shí)takeUnless函數(shù)返回null。

使用場(chǎng)景:只需要單個(gè)if分支語(yǔ)句的時(shí)候
優(yōu)點(diǎn):
可以配合其他作用域函數(shù)返回的結(jié)果蜕煌,做出單向判斷派阱,保持鏈?zhǔn)秸{(diào)用
簡(jiǎn)化寫(xiě)法,邏輯清晰斜纪,減少代碼量贫母,代碼更優(yōu)雅

init

主構(gòu)造函數(shù)里不能寫(xiě)代碼,那我們?cè)趺闯跏蓟@個(gè)類的代碼呢盒刚?Kotlin則是提供了初始化模塊腺劣,基本上就是用init修飾符修飾一個(gè){},在類初始化時(shí)執(zhí)行這段代碼因块。

    class User() {
        init {

        }
    }

數(shù)組

創(chuàng)建數(shù)組
        var names = arrayOf("小王", "小花", "小紅", "小明")

        var ages = arrayOf(22, 19, 18)

        var array = arrayOfNulls<String>(5)   //創(chuàng)建空數(shù)組
        array.set(1, "哈哈")   //賦值
數(shù)組遍歷
    fun arrayForEach() {
        var names = arrayOf("小王", "小花", "小紅", "小明")
        for (i in 1..5 step 1) {   //跳過(guò)第1步遍歷

        }

        for (i in 0..names.size-1) {  //遍歷names數(shù)組橘原,相當(dāng)于java里  for (int i=0:i<names.length;i++)

        }

        for (i in names.indices) {  //正序遍歷

        }

        for (i in 1 until 10){    //為一個(gè)左閉右開(kāi)的區(qū)間,打印1到9
            print("$i")
        }

        for (i in names.size downTo 0) {  //倒序遍歷

        }

        for (i in names.reversed()) {  //反轉(zhuǎn)遍歷數(shù)組

        }

        repeat(10) {  //打印0到9
            print(it)
        }

        names.forEach {  //forEach函數(shù)遍歷涡上,Kotlin里的集合都自帶foreach函數(shù)

        }

        names.forEachIndexed { index, s ->   //帶position的遍歷
            
        }
    }

in的用法:val num = 1..10趾断,表示變量num是一個(gè)[1,10]的區(qū)間。
step表步長(zhǎng)吩愧,表示遍歷間隔的個(gè)數(shù)芋酌。

類與對(duì)象

類構(gòu)造函數(shù)

在 Kotlin 中的一個(gè)類可以有一個(gè)主構(gòu)造函數(shù)以及一個(gè)或多個(gè)次構(gòu)造函數(shù)。如果主構(gòu)造函數(shù)沒(méi)有任何注解或者可見(jiàn)性修飾符耻警,可以省略這個(gè) constructor 關(guān)鍵字。

class User constructor(name: String, age: Int, id: Int)

class User(name: String, age: Int, id: Int)

操作示例:

class User(val name: String) { //主構(gòu)造函數(shù)
    var age = 0
    var sex = "man"

    /**
     * 有參次構(gòu)造方法
     */
    constructor(name: String, age: Int, id: Int): this(name) {  //次構(gòu)造函數(shù),必須去調(diào)用主構(gòu)造

    }
    constructor(name: String, sex: String): this(name) {
        this.sex = sex
    }

    /**
     * 無(wú)參次構(gòu)造方法
     */
    constructor(): this("暫無(wú)名字") {

    }

    init {
        println("name is $name")
        println("age is $age")
    }

    fun main() {
        User()   //次構(gòu)造
        User("小明")  //主構(gòu)造
        User("小明", 18, 1)  //次構(gòu)造
    }
}
創(chuàng)建對(duì)象

Kotlin中創(chuàng)建對(duì)象不再需要關(guān)鍵字new了甘穿,直接創(chuàng)建對(duì)象:

var user = User()
繼承

在Kotlin中的類和方法默認(rèn)是不可以被繼承的腮恩,需要加上關(guān)鍵字open,才允許被繼承温兼。繼承用":"表示秸滴,類和接口的繼承都用":",類需要加()募判。

class VipUser : User(), Use {}

open class User {}

interface Use {}
內(nèi)部類
class OuterClass {

    val outerInfo: String = "outerInfo"

    fun show() {
        InnerClass().show() //外部類可以訪問(wèn)內(nèi)部類
    }

    //加上inner關(guān)鍵字才是內(nèi)部類荡含,內(nèi)部類才能和外部類相互訪問(wèn),否則不是內(nèi)部類而是嵌套類
    inner class InnerClass {
        fun show() = println("my outerclass info: " + outerInfo) //內(nèi)部類也可以訪問(wèn)外部類
    }
}
數(shù)據(jù)類

即為我們通常使用的bean類届垫,一般在定義數(shù)據(jù)類的時(shí)候释液,我們需要手動(dòng)實(shí)現(xiàn)這個(gè)類的equals()、hashcode()装处、toString()等方法误债,這些方法是必要的。但是加上data關(guān)鍵字后妄迁,該類會(huì)自動(dòng)生成這些方法寝蹈。

data class User(var name: String) {

}
單例類

在java中,單例的寫(xiě)法需要自己手動(dòng)實(shí)現(xiàn)登淘,比如用懶漢式還是餓漢式箫老。但是在Kotlin中單例就非常簡(jiǎn)化了,只需要將class替換成object就可以了黔州。

    object SingleTonClass {

        var params: String? = null

        fun function() {

        }
    }

    SingleTonClass.function()

    SingleTonClass.params

使用單例時(shí)不需要再獲取instance實(shí)例對(duì)象了耍鬓,Kotlin已經(jīng)在內(nèi)部幫我們創(chuàng)建了一個(gè)單例的實(shí)例,直接使用類名調(diào)用它的屬性和方法辩撑。

compaion object(伴生對(duì)象)

在java中static表靜態(tài)變量界斜,kotlin中取消了static,用compaion object來(lái)代替它的用法合冀。

class Companionobject {

    //伴生對(duì)象的由來(lái)各薇,是kotlin沒(méi)有static靜態(tài)
    //不管對(duì)象創(chuàng)建多少個(gè),companion object只會(huì)初始化一次
    companion object {
        val info = "lili" //靜態(tài)變量

        fun showInfo() {
            println(info)
        }
    }

    fun test() {
        //背后代碼:生成了 Companionobject.companion類
        println(info)

        showInfo()
    }
}
Kotlin 接口
//kotlin的接口
//接口里面的所有成員和方法和接口本身都是 public open的
//實(shí)現(xiàn)類不僅要重寫(xiě)接口的函數(shù)君躺,還要重寫(xiě)接口的成員
interface IUSB {
    var usbVersionInfo: String

    fun insertUSB(): String
}

//成員重寫(xiě)寫(xiě)到實(shí)現(xiàn)類的構(gòu)造方法中 方式
class Mouse(override var usbVersionInfo: String = "USB 3.0") : IUSB {
    override fun insertUSB(): String = usbVersionInfo
}

//成員重寫(xiě)寫(xiě)到實(shí)現(xiàn)類中的方式
class KeyBorad: IUSB {
    override var usbVersionInfo: String = "USB 3.0"
        get() {  //get/set 方法會(huì)調(diào)用代碼塊內(nèi)容峭判,并返回一個(gè)值
            println("獲取了 usbVersionInfo ${usbVersionInfo}")
            return field
        }
        set(value) {
            println("設(shè)置了 usbVersionInfo ${usbVersionInfo}")
            field = value //field表示該 usbVersionInfo 屬性
        }

    override fun insertUSB(): String = "keyboard $usbVersionInfo"

}

fun showInterface() {
    val usb1 = Mouse()
    usb1.insertUSB()

    val usb2 = KeyBorad()
    usb2.usbVersionInfo = "sfd" //使用屬性調(diào)用get()  賦值屬性調(diào)用set()
    usb2.insertUSB()
}
JvmField JvmStatic
// JvmStatic JvmField注解使用
//用于 Java調(diào)用kotlin 屬性和方法 兼容性 而產(chǎn)生的
//JvmField注解使用 將默認(rèn)的private修改成了public訪問(wèn)符
//JvmStatic 將 companion object 中的 屬性、方法能像kotlin一樣能直接調(diào)用
class Personz {
    @JvmField
    val names = listOf("lala", "haha", "yaya")

    //這個(gè) names轉(zhuǎn)成java就是如下代碼棕叫, val修飾的 names屬性成了 private final 林螃,外部調(diào)用不到,而提供了一個(gè)方法獲取
    // 使用了 @JvmField注解俺泣,將該屬性從private變成public疗认,能直接獲取val修飾的屬性
    /**
     * public final class Personz {
     *    @NotNull
     *    private final List names = CollectionsKt.listOf(new String[]{"lala", "haha", "yaya"});
     *
     *    @NotNull
     *    public final List getNames() {
     *       return this.names;
     *    }
     * }
     */

    companion object {
        @JvmField
        val name : String = "lala"

        @JvmStatic
        fun printlnPersonName() = println("名字: " + name)
    }
}

//java中調(diào)用代碼
    public void getJvmFieldStatic() {
//        new Personz().getNames();  //沒(méi)加 jvmField的調(diào)用
        List<String> names = new Personz().names; //加了 jvmField的調(diào)用

        //沒(méi)加 JvmStatic完残,java調(diào)用 Companion object需要加一層 Companion類來(lái)調(diào)用
//        Personz.Companion.getName();
//        Personz.Companion.printlnPersonName();

        String name = Personz.name;
        //加上 JvmStatic,就有了和Kotlin一樣的調(diào)用效果横漏,把函數(shù)寫(xiě)到了 Companion類 外面
        Personz.printlnPersonName();
    }
range符
    fun range(number: Int) {
        //range 范圍
        if (number in 10..59) {
            println("不及格")
        } else if (number in 0 .. 9) {
            println("很差")
        } else if (number in 60..100) {
            println("及格")
        } else {
            println("分?jǐn)?shù)不合法")
        }
    }
將現(xiàn)有Java文件轉(zhuǎn)換為Kotlin文件

右鍵->Convert Java File to Kotlin File
我們可以將現(xiàn)有Java文件代碼轉(zhuǎn)換為Kotlin文件代碼谨设,而實(shí)現(xiàn)從java往kotlin上轉(zhuǎn)移《薪剑可以針對(duì)單個(gè)文件扎拣,某個(gè)包,某個(gè)module素跺,或者整個(gè)項(xiàng)目轉(zhuǎn)為kotlin文件二蓝。
轉(zhuǎn)換完成之后可能會(huì)有少量語(yǔ)法錯(cuò)誤,需要手動(dòng)修改一下指厌。

將kotlin代碼轉(zhuǎn)為java

在Tools->Kotlin->show Kotlin ByteCode刊愚,點(diǎn)擊Decompile轉(zhuǎn)回類似Java代碼。

教程參考:

https://www.bilibili.com/video/BV1kT4y1o7nP

Github代碼地址:

https://github.com/running-libo/KotlinPractise

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末仑乌,一起剝皮案震驚了整個(gè)濱河市百拓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌晰甚,老刑警劉巖衙传,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異厕九,居然都是意外死亡蓖捶,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)扁远,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)俊鱼,“玉大人,你說(shuō)我怎么就攤上這事畅买〔⑾校” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵谷羞,是天一觀的道長(zhǎng)帝火。 經(jīng)常有香客問(wèn)我,道長(zhǎng)湃缎,這世上最難降的妖魔是什么犀填? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮嗓违,結(jié)果婚禮上九巡,老公的妹妹穿的比我還像新娘。我一直安慰自己蹂季,他們只是感情好冕广,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布疏日。 她就那樣靜靜地躺著,像睡著了一般撒汉。 火紅的嫁衣襯著肌膚如雪制恍。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天神凑,我揣著相機(jī)與錄音,去河邊找鬼何吝。 笑死溉委,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的爱榕。 我是一名探鬼主播瓣喊,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼黔酥!你這毒婦竟也來(lái)了藻三?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤跪者,失蹤者是張志新(化名)和其女友劉穎棵帽,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體渣玲,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡逗概,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了忘衍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逾苫。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖枚钓,靈堂內(nèi)的尸體忽然破棺而出铅搓,到底是詐尸還是另有隱情,我是刑警寧澤搀捷,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布星掰,位于F島的核電站,受9級(jí)特大地震影響指煎,放射性物質(zhì)發(fā)生泄漏蹋偏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一至壤、第九天 我趴在偏房一處隱蔽的房頂上張望威始。 院中可真熱鬧,春花似錦像街、人聲如沸黎棠。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)脓斩。三九已至木西,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間随静,已是汗流浹背八千。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留燎猛,地道東北人恋捆。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像重绷,于是被迫代替她去往敵國(guó)和親沸停。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345