Kotlin入坑基礎(chǔ)篇二

Kotlin入坑基礎(chǔ)篇一

這一篇主要講解kotlin進(jìn)階,內(nèi)容主要有以下:
空安全
kotlin單例
函數(shù)擴(kuò)展
智能轉(zhuǎn)換

空安全

Kotlin中添加了對空的保護(hù)

fun testKotlinNPE() {
        var s: String = "Hubery"
        s = null//會導(dǎo)致編譯不過
        var s2: String? = "Hubery"
        s2 = null//s2可以為空,能夠編譯通過

        print(s.length)//因為不為空,所以直接調(diào)用length不會出現(xiàn)異常

        print(s2.length)//編譯不通過,會要求添加?.或者!!.進(jìn)行調(diào)用
        print(s2!!.length)//編譯能夠通過,不過s2如果是null,那么將會導(dǎo)致調(diào)用length的時候出現(xiàn)空指針
        print(s2?.length)//使用安全操作符,如果s2為null,那么就不會調(diào)用length,也就不會導(dǎo)致異常,不過需要注意的是s2?.length可能整體為null;如果別的地方使用需要注意

        //Elvis操作符   
        val i = s2?.length ?:0//如果s2為空,那么就不會調(diào)用.length方法,而直接返回右邊的0
    }

使用Elvis操作符,可以val i = s2?.length ?:0如果s2為空,那么就不會調(diào)用.length方法,而直接返回右邊的0。

kotlin單例

我們都知道單例分為懶漢式與餓漢式,同時可以對單例進(jìn)行線程同步等;
我們先來看看一個java的例子:

/**
 * Created by hubery on 2018/7/18.
 * 餓漢模式
 */
public class DemoSingleton {
    private static DemoSingleton INSTANCE = new DemoSingleton();

    public static DemoSingleton getInstance() {
        return INSTANCE;
    }
}

上面展示的例子就是java的餓漢式模式;那么kotlin的餓漢模式是怎么樣的呢?

/**
 * Created by hubery on 2018/7/18.
 * kotlin的惡漢模式
 */
object DemoSingleton

沒有看錯就只有一句話,關(guān)鍵字object修飾。當(dāng)然這里因為類里面沒有方法因此省略了{},因為懶漢式是非線程安全的,多線程中使用可能會出現(xiàn)創(chuàng)建多個對象,因此,我們需要用到懶漢式單例,我們把上面的例子稍微改造一下:

public class DemoSingleton {
    private static DemoSingleton INSTANCE;

    public static DemoSingleton getInstance() {
        if(INSTANCE == null){
            INSTANCE = new DemoSingleton();
        }
        return INSTANCE;
    }
}

上面的java例子也就相比之前的餓漢式多了一個null的判斷,再看看kotlin的實現(xiàn):

/**
 * Created by hubery on 2018/7/18.
 * kotlin的懶漢式單例
 */
class DemoSingleton {
    companion object {
        val INSTANCE by lazy(LazyThreadSafetyMode.NONE) {
            DemoSingleton()
        }
    }
}

kotlin的懶漢式單例中使用到了伴生對象companion object,它相當(dāng)于java中的公共靜態(tài),然后使用到了LazyThreadSafetyMode枚舉里面的NONE

public enum class LazyThreadSafetyMode {
    /**
     * Locks are used to ensure that only a single thread can initialize the [Lazy] instance.
     */
    SYNCHRONIZED,
    /**
     * Initializer function can be called several times on concurrent access to uninitialized [Lazy] instance value,
     * but only the first returned value will be used as the value of [Lazy] instance.
     */
    PUBLICATION,
    /**
     * No locks are used to synchronize an access to the [Lazy] instance value; if the instance is accessed from multiple threads, its behavior is undefined.
     *
     * This mode should not be used unless the [Lazy] instance is guaranteed never to be initialized from more than one thread.
     */
    NONE,
}

通過上面的注釋,可以看出NONE表示是沒有加鎖,因此不是線程安全的,當(dāng)然也可以使用SYNCHRONIZED,PUBLICATION。

上面的例子都會有線程安全問題,現(xiàn)在我們繼續(xù)對代碼進(jìn)行改進(jìn),使用SYNCHRONIZED進(jìn)行加鎖:

/**
 * Created by hubery on 2018/7/18.
 * 懶漢模式
 */
public class DemoSingleton {
    private static DemoSingleton INSTANCE;

    public static synchronized DemoSingleton getInstance() {
        if(INSTANCE == null){
            INSTANCE = new DemoSingleton();
        }
        return INSTANCE;
    }
}

同樣的kotlin也可以使用synchronized進(jìn)行加鎖:

/**
 * Created by hubery on 2018/7/18.
 * kotlin的懶漢式單例
 */
class DemoSingleton {
    companion object {
        private var INSTANCE:DemoSingleton? = null

        @Synchronized
        fun getInstance():DemoSingleton{
            if(INSTANCE == null){
                INSTANCE = DemoSingleton()
            }
            return INSTANCE!!
        }
    }
}

kotlin中使用的是@Synchronized注解方式達(dá)到同步的效果;同樣的,我們知道上面的例子同樣存在不足,我們要實現(xiàn)只有第一次獲取的時候才會加鎖,那么我們使用雙重檢測。

/**
 * Created by hubery on 2018/7/18.
 * 懶漢模式
 */
public class DemoSingleton {
    private static volatile DemoSingleton INSTANCE;
    public static DemoSingleton getInstance() {
        if (INSTANCE == null) {
            synchronized (DemoSingleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new DemoSingleton();
                }
            }
        }
        return INSTANCE;
    }
}

使用kotlin實現(xiàn)

/**
 * Created by hubery on 2018/7/18.
 * kotlin的懶漢式單例
 */
class DemoSingleton {
    companion object {
        val INSTANCE by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
            DemoSingleton()
        }
    }
}

最后說一下內(nèi)部類式

public class DemoSingleton {
    private DemoSingleton() {
    }

    private static class Instance {
        private static DemoSingleton singleton = new DemoSingleton();
    }

    public static DemoSingleton getInstance() {
        return Instance.singleton;
    }
}

kotlin的寫法

class DemoSingleton {
    companion object {
        fun getInstance() = Instance.INSTANCE
    }

    private object Instance {
        val INSTANCE = DemoSingleton()
    }
}

利用了classloader的機(jī)制來保證初始化instance時只有一個線程,所以也是線程安全的,同時沒有性能損耗。
對比kotlin和java的單例,總體說來kotlin的單例比java單例實現(xiàn)代碼更加的簡潔,且kotlin語言對單例的支持更加的友好。

函數(shù)擴(kuò)展

擴(kuò)展函數(shù)可以在已有類中添加新的方法,不會對原類做修改,擴(kuò)展函數(shù)定義形式。其中擴(kuò)展函數(shù)的參數(shù)可以為空。

fun 擴(kuò)展函數(shù)的對象.擴(kuò)展函數(shù)的名字(擴(kuò)展函數(shù)的參數(shù)){

}

先來看看基本的函數(shù)擴(kuò)展:

open class Personal(var name: String) {
}

/**
 * 擴(kuò)展函數(shù)
 */
fun Personal.test(name: String): String {
    return "這是一個擴(kuò)展類,名字=$name"
}

/**
 * 方法測試
 */
fun test(){
    var personal = Personal("Hubery")
    personal.test("test()")
}

上面的例子展示了為Personal對象擴(kuò)展一個test方法;

擴(kuò)展函數(shù)是靜態(tài)解析的,并不是接收者類型的虛擬成員,在調(diào)用擴(kuò)展函數(shù)時,具體被調(diào)用的的是哪一個函數(shù),由調(diào)用函數(shù)的的對象表達(dá)式來決定的,而不是動態(tài)的類型決定的:

擴(kuò)展函數(shù)不僅可以擴(kuò)展方法,還可以對屬性進(jìn)行擴(kuò)展,或者伴生類進(jìn)行函數(shù)或者屬性進(jìn)行擴(kuò)展。

智能轉(zhuǎn)換

關(guān)于智能轉(zhuǎn)換,我們用一個例子來說明,先來看看java中的例子:

public interface Ball {
        void pay(String name);
    }

    class BasketBall implements Ball {
        @Override
        public void pay(String name) {
        }
    }

    class FootBall implements Ball {
        @Override
        public void pay(String name) {
        }
    }

    void test(Ball ball) {
        if (ball instanceof BasketBall) {//籃球
            BasketBall basketBall = (BasketBall) ball;
            basketBall.pay("籃球");
        } else if (ball instanceof FootBall) {
            FootBall footBall = (FootBall) ball;
            footBall.pay("足球");
        }
    }

定義一個Ball接口,那么分別用BasketBall,FootBall去實現(xiàn)它,在測試的時候,分別用instanceof去判斷,然后再分別強(qiáng)轉(zhuǎn)成相應(yīng)的類型。

interface Ball {
    fun pay(name: String) {
        print("pay() 我們正在玩$name")
    }
}

class BasketBall : Ball {
    override fun pay(name: String) {
        super.pay(name)
    }

    fun basketBallPay() {

    }
}

class FootBall : Ball {
    override fun pay(name: String) {
        super.pay(name)
    }

    fun footBallPay() {

    }
}

fun test(ball: Ball) {
    if (ball is BasketBall) {
        var basketBall = ball.basketBallPay()
        ball.pay("籃球")
    } else if (ball is FootBall) {
        var footBall = ball.footBallPay()
        ball.pay("足球")
    }
}

由上面可以看到,kotlin在使用的時候不同于java需要強(qiáng)制轉(zhuǎn)換,kotlin它合并了類型檢查和轉(zhuǎn)換。這就是kotlin的智能轉(zhuǎn)換。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容