這一篇主要講解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)//因?yàn)椴粸榭蘸酶郏灾苯诱{(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)然這里因?yàn)轭惱锩鏇]有方法因此省略了{}
,因?yàn)閼袧h式是非線程安全的螺垢,多線程中使用可能會出現(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的實(shí)現(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á)到同步的效果;同樣的搔耕,我們知道上面的例子同樣存在不足隙袁,我們要實(shí)現(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實(shí)現(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單例實(shí)現(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去實(shí)現(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)換分俯。