從 JAVA 到 Kotlin

自Kotlin被google官方認(rèn)可之后回懦,Android界對(duì)Kotlin的熱度便持續(xù)上漲,在了解了它的優(yōu)勢(shì)后,作為一名與時(shí)俱進(jìn)的Android開發(fā)工程師癌蓖,是時(shí)候有必要來學(xué)習(xí)Kotlin了。

Kotlin有何優(yōu)勢(shì)婚肆?

  • 代碼的大幅度精簡(jiǎn)
  • 100% 兼容 Java 代碼

以上兩點(diǎn)是我認(rèn)為Kotlin的最大優(yōu)勢(shì)租副,目前java 的主流開發(fā)工具基本都支持了java轉(zhuǎn)Kotlin,因此轉(zhuǎn)換基本不需要什么成本较性,就算在使用過程中遇到坑用僧,完全可以用java來寫结胀,無隔閡的運(yùn)行,一開始不熟悉的時(shí)候還可以用java編寫后轉(zhuǎn)成Kotlin责循,不斷對(duì)比就會(huì)逐漸熟悉糟港。(ps:一個(gè)好的IDE對(duì)學(xué)習(xí)也是非常有幫助,在寫Kotlin的代碼時(shí)android studio 經(jīng)常會(huì)提醒我有簡(jiǎn)化的寫法)

Kotlin基礎(chǔ)語法

Kotlin教程

Kotlin在線學(xué)習(xí)工具
Kotlin 中文站

對(duì)比學(xué)習(xí)

kotlin中一切皆為對(duì)象 院仿,沒有像java一般的基本數(shù)據(jù)類型秸抚,數(shù)值類型為:Int, Float, Double等都是對(duì)象(類似java的包裝類);函數(shù)也是對(duì)象歹垫,可作為參數(shù)和返回值剥汤。

定義常量與變量

可變變量定義:var 關(guān)鍵字

var <標(biāo)識(shí)符> : <類型> = <初始化值>

不可變變量定義:val 關(guān)鍵字,只能賦值一次的變量(類似Java中final修飾的變量)

val <標(biāo)識(shí)符> : <類型> = <初始化值>

類型檢測(cè)及自動(dòng)類型轉(zhuǎn)換

我們可以使用 is 運(yùn)算符檢測(cè)一個(gè)表達(dá)式是否某類型的一個(gè)實(shí)例(類似于Java中的instanceof關(guān)鍵字)排惨。

fun getStringLength(obj: Any): Int? {
  if (obj is String) {
    // 做過類型判斷以后吭敢,obj會(huì)被系統(tǒng)自動(dòng)轉(zhuǎn)換為String類型
    return obj.length 
  }
}
  • Kotlin中的Any = Java中的Object

類型強(qiáng)轉(zhuǎn)

類型強(qiáng)轉(zhuǎn)在Android中非常常見,如:

GridView gridView = (GridView) findViewById(R.id.grid_view);

而Kotlin中使用as關(guān)鍵詞:

val recyclerView = findViewById(R.id.recycler_view) as RecyclerView

字符串模板

$ 表示一個(gè)變量名或者變量值
$varName 表示變量值
${varName.fun()} 表示變量的方法返回值:

var a = 1
// 模板中的簡(jiǎn)單名稱:
val s1 = "a is $a" 

a = 2
// 模板中的任意表達(dá)式:
val s2 = "${s1.replace("is", "was")}, but now is $a"

static : companion object

java中static表示類相關(guān)的暮芭,生命周期于類相同鹿驼,Android中經(jīng)常會(huì)用來聲明一些static常量和工具類的static方法

public static final int A = 1;
public static final String STR = "abc";

public static int getInt() {
        return A;
    }

在Kotlin中則沒有static關(guān)鍵字,取而代之的是companion object (伴生對(duì)象)

companion object{
        val A = 1 //val表示不可變辕宏,類似java的 final
        val STR = "abc"
    }

在Android中常見的utils類(只有靜態(tài)方法)可以變成這樣:

class Utils private constructor() {

    init {
        throw AssertionError()
    }

    companion object {
        fun staticFun() {/*do someting*/
        }
    }
}

當(dāng)然畜晰,這是java思維下Kotlin轉(zhuǎn)變,實(shí)際上用Kotlin實(shí)現(xiàn)工具類還有其他的方法匾效,其一是使用object:

object Utils {

    /** 獲得狀態(tài)欄的高度  */
    @JvmStatic
    fun getStatusHeight(context: Context): Int {
        var statusHeight = -1
        try {
            val clazz = Class.forName("com.android.internal.R\$dimen")
            val obj = clazz.newInstance()
            val height = Integer.parseInt(clazz.getField("status_bar_height").get(obj).toString())
            statusHeight = context.resources.getDimensionPixelSize(height)
        } catch (e: Exception) {
            e.printStackTrace()
        }

        return statusHeight
    }
}

注意@JvmStatic舷蟀,代表了在Java調(diào)用時(shí)也可以像static方式那樣使用:Utils.getStatusHeight() ,如果不加這個(gè)注解的話在java中調(diào)用Utils.INSTANCE.getStatusHeight()面哼。
還有另一種方式頂層函數(shù)野宜,也是Kotlin實(shí)戰(zhàn)這本書中推薦的方式,不需要?jiǎng)?chuàng)建類魔策,而是直接創(chuàng)建一個(gè).kt文件定義函數(shù)(方法):

@file:JvmName("ScreenUtil")//定義java中的類名

package com.huburt.library.util

import android.content.Context

/**
 * Created by hubert
 *
 * Created on 2017/11/2.
 */
fun getStatusHeight(context: Context): Int {
    var statusHeight = -1
    try {
        val clazz = Class.forName("com.android.internal.R\$dimen")
        val obj = clazz.newInstance()
        val height = Integer.parseInt(clazz.getField("status_bar_height").get(obj).toString())
        statusHeight = context.resources.getDimensionPixelSize(height)
    } catch (e: Exception) {
        e.printStackTrace()
    }
    return statusHeight
}

Kotlin中可以直接使用該方法匈子,會(huì)自動(dòng)導(dǎo)入import com.huburt.library.util.getStatusHeight,java中使用還是會(huì)像使用static方法一樣ScreenUtil.getStatusHeight(this);闯袒,如果沒有定義java類名@file:JvmName("ScreenUtil")的話虎敦,會(huì)默認(rèn)使用.kt的文件名+Kt,如這里我是放在ScreenUtil.kt文件中政敢,使用就是ScreenUtilKt.getStatusHeight(this);

既然Kotlin沒有static關(guān)鍵字其徙,java中較多使用的

單例模式

class Singleton {
    private Singleton() {
        System.out.print("This is a singleton");
    }

    private static class Holder {
        private static final Singleton instance = new Singleton();
    }

    public static Singleton getInstance() {
        return Holder.instance;
    }
}

在Kotlin中也需要作出改變

class Singleton private constructor() {
    init {
        println("This ($this) is a singleton")
    }

    private object Holder {
        val INSTANCE = Singleton()
    }

    companion object {
        val instance: Singleton by lazy { Holder.INSTANCE }
    }
}

構(gòu)造

可以看到Kotlin的constructor(構(gòu)造器)位置與java中不同。
Koltin 中的類可以有一個(gè) 主構(gòu)造器喷户,以及一個(gè)或多個(gè)次構(gòu)造器唾那,主構(gòu)造器是類頭部的一部分,位于類名稱之后:
class Person constructor(firstName: String) {}
如果主構(gòu)造器沒有任何注解褪尝,也沒有任何可見度修飾符闹获,那么constructor關(guān)鍵字可以省略期犬。
class Person(firstName: String) {}
主構(gòu)造器中不能包含任何代碼,初始化代碼可以放在初始化代碼段中避诽,初始化代碼段使用 init 關(guān)鍵字作為前綴龟虎。

class Person constructor(firstName: String) {
    init {
        System.out.print("FirstName is $firstName")
    }
}

注意:主構(gòu)造器的參數(shù)可以在初始化代碼段中使用,也可以在類主體n定義的屬性初始化代碼中使用沙庐。 一種簡(jiǎn)潔語法鲤妥,可以通過主構(gòu)造器來定義屬性并初始化屬性值(可以是var或val):

class People(val firstName: String, val lastName: String) {
    //...
}

如果類有主構(gòu)造函數(shù),每個(gè)次構(gòu)造函數(shù)都要轨功,或直接或間接通過另一個(gè)次構(gòu)造函數(shù)代理主構(gòu)造函數(shù)旭斥。在同一個(gè)類中代理另一個(gè)構(gòu)造函數(shù)使用 this 關(guān)鍵字:

class Person() {
    var parent: Person? = null

    constructor(parent: Person) : this() {
        this.parent = parent
    }
}

對(duì)象

Kotlin中創(chuàng)建對(duì)象不需要 new ,只需要調(diào)用構(gòu)造器如:var person = Person()

匿名內(nèi)部類

Android中對(duì)于匿名內(nèi)部類的使用也非常多容达,典型的setOnClickLsitener ,而在Kotlin中使用object關(guān)鍵字實(shí)現(xiàn)匿名內(nèi)部類:

button.setOnClickListener(object: OnClickListener {
    override fun onClick(v: View?){}
})

javaBean

javaBean也是Android開發(fā)中非常常見的古涧,用于封裝數(shù)據(jù),這是一個(gè)基本的網(wǎng)絡(luò)結(jié)果實(shí)體類

public class BaseEntity<T> {
    private int code;
    private String message;
    private T data;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

用Kotlin去聲明的話:

class BaseEntity<T> {
    var code: Int = 0
//        set //默認(rèn)實(shí)現(xiàn)
//        get
    var message: String? = null
    var data: T? = null

}

不要認(rèn)為這只是java中public聲明的屬性花盐,這些屬性都有默認(rèn)實(shí)現(xiàn)的getter/setter羡滑,如果不想某個(gè)屬性被修改(只讀)只需要在set前聲明 private

還有另外一種更簡(jiǎn)便的寫法算芯,Kotlin中定義了一種數(shù)據(jù)類,可以創(chuàng)建一個(gè)只包含數(shù)據(jù)的類柒昏,使用關(guān)鍵字為 data:

data class DataClassExample (val x: Int, val y: Int, val z: Int)

編譯器會(huì)自動(dòng)的從主構(gòu)造函數(shù)中根據(jù)所有聲明的屬性提取以下函數(shù):

  • equals() / hashCode()
  • toString() 格式如 "User(name=John, age=42)"
  • componentN() functions 對(duì)應(yīng)于屬性,按聲明順序排列
  • copy() 函數(shù)

如果這些函數(shù)在類中已經(jīng)被明確定義了熙揍,或者從超類中繼承而來职祷,就不再會(huì)生成。

為了保證生成代碼的一致性以及有意義届囚,數(shù)據(jù)類需要滿足以下條件:

  • 主構(gòu)造函數(shù)至少包含一個(gè)參數(shù)有梆。
  • 所有的主構(gòu)造函數(shù)的參數(shù)必須標(biāo)識(shí)為val 或者 var ;
  • 數(shù)據(jù)類不可以聲明為 abstract, open, sealed 或者 inner;
  • 數(shù)據(jù)類不能繼承其他類 (但是可以實(shí)現(xiàn)接口)。

var message: String? 是否對(duì)這個(gè)?感到奇怪意系。其實(shí)這是表示這個(gè)屬性可能為null泥耀,在使用的時(shí)候需要進(jìn)行處理。

NULL檢查機(jī)制

在Android中使用變量前我們需要對(duì)其進(jìn)行空判斷避免空指針蛔添,這樣往往帶來帶來大量的工作痰催,這些空判斷代碼本身沒有什么實(shí)際意義,并且讓代碼的可讀性和簡(jiǎn)潔性帶來了巨大的挑戰(zhàn)迎瞧。除此之外夸溶,我們經(jīng)常會(huì)忘記判空!P坠琛缝裁!

Kotlin 為了解決這個(gè)問題,它并不允許我們直接使用一個(gè)可選型的變量去調(diào)用方法或者屬性咏尝。對(duì)于聲明可為空的參數(shù)压语,在使用時(shí)要進(jìn)行空判斷處理啸罢,有兩種處理方式,字段后加!!像Java一樣拋出空異常胎食,另一種字段后加?可不做處理返回值為 null或配合?:做空判斷處理

//類型后面加?表示可為空
var age: String? = "23" 
//拋出空指針異常
val ages = age!!.toInt()
//不做處理返回 null
val ages1 = age?.toInt()
//age為空返回-1
val ages2 = age?.toInt() ?: -1 //等價(jià)于 if (age != null) age.toInt() else -1

方法(函數(shù))

java中的方法:

public int funName() {
        return 1;
    }

而在Kotlin函數(shù)定義使用關(guān)鍵字 fun扰才,參數(shù)格式為:參數(shù) : 類型

fun sum(a: Int, b: Int): Int {   // Int 參數(shù),返回值 Int
    return a + b
}

可變長(zhǎng)參數(shù)函數(shù)

java中使用...表示可變參數(shù)
函數(shù)的變長(zhǎng)參數(shù)可以用 vararg 關(guān)鍵字進(jìn)行標(biāo)識(shí):

fun vars(vararg v:Int){
    for(vt in v){
        print(vt)
    }
}

todo

之前用java開發(fā)Android的時(shí)候厕怜,對(duì)于一些放在之后實(shí)現(xiàn)的功能衩匣,為了防止忘記,會(huì)加上//TODO粥航,以方便自己后續(xù)記得在此處補(bǔ)上實(shí)現(xiàn)琅捏。而在Kotlin中,輸入todo递雀,IDE提示的是一個(gè)TODO("xxx")的函數(shù)柄延,功能類似,只是在調(diào)用此處方法的時(shí)候回拋出一個(gè)異常:

kotlin.NotImplementedError: An operation is not implemented: xxx
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缀程,一起剝皮案震驚了整個(gè)濱河市搜吧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌杨凑,老刑警劉巖滤奈,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異撩满,居然都是意外死亡蜒程,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門伺帘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昭躺,“玉大人,你說我怎么就攤上這事曼追∏涎觯” “怎么了?”我有些...
    開封第一講書人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵礼殊,是天一觀的道長(zhǎng)驹吮。 經(jīng)常有香客問我,道長(zhǎng)晶伦,這世上最難降的妖魔是什么碟狞? 我笑而不...
    開封第一講書人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮婚陪,結(jié)果婚禮上族沃,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好脆淹,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開白布常空。 她就那樣靜靜地躺著,像睡著了一般盖溺。 火紅的嫁衣襯著肌膚如雪漓糙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,736評(píng)論 1 312
  • 那天烘嘱,我揣著相機(jī)與錄音昆禽,去河邊找鬼。 笑死蝇庭,一個(gè)胖子當(dāng)著我的面吹牛醉鳖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播哮内,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼盗棵,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了牍蜂?” 一聲冷哼從身側(cè)響起漾根,我...
    開封第一講書人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鲫竞,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逼蒙,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡从绘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了是牢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片僵井。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖驳棱,靈堂內(nèi)的尸體忽然破棺而出批什,到底是詐尸還是另有隱情,我是刑警寧澤社搅,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布驻债,位于F島的核電站,受9級(jí)特大地震影響形葬,放射性物質(zhì)發(fā)生泄漏合呐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一笙以、第九天 我趴在偏房一處隱蔽的房頂上張望淌实。 院中可真熱鬧,春花似錦、人聲如沸拆祈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽放坏。三九已至凛剥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間轻姿,已是汗流浹背犁珠。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留互亮,地道東北人犁享。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像豹休,于是被迫代替她去往敵國(guó)和親炊昆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容