Kotlin 中的伴生對象和靜態(tài)成員

轉(zhuǎn)載請注明出處:http://www.reibang.com/p/e6883f85a1bc
本文出自Shawpoo的簡書
我的博客:CSDN博客

一、前言

最近公司開發(fā)的項目使用的是 Kotlin,所以不得不學(xué)起來 Kotlin 這門語言了剧蹂,畢竟是 Android 官方的第一開發(fā)語言嘛闸餐!在平時的開發(fā)中殷费,我習(xí)慣將啟動 Activity 的方法以靜態(tài)方法的形式定義在目標(biāo) Activity 中勇婴,如下:

public static final String EXTRA_PARAMS = "extra_params";

public static void open(Context context, String params) {
    Intent intent = new Intent(context, TestActivity.class);
    intent.putExtra(EXTRA_PARAMS, params);
    context.startActivity(intent);
}

這樣寫的好處就是方便調(diào)用者調(diào)用蒙幻,調(diào)用者可以清晰的知道目標(biāo) Activity 需要什么參數(shù),而且不用關(guān)心傳參的 key衣迷。但是在 Kotlin 中并不沒有 static 這個關(guān)鍵字畏鼓,該如何處理呢?這里需要用到 Kotlin 的伴生對象來處理壶谒。所以本文主要介紹 Kotlin 中伴生對象的應(yīng)用滴肿。

二、伴生對象

1佃迄、聲明:

Kotlin 中,在類中定義的對象(object)聲明贵少,可使用 companion 修飾呵俏,這樣此對象(object)就是伴生對象了。如下例子:

class NumberTest {
    companion object Obj {  
        var flag = false

        fun plus(num1: Int, num2: Int): Int {
            return num1 + num2
        }
    }
}

在本例中滔灶,類 NumberTest 中就聲明了一個伴生對象普碎,包含屬性 flag 和 方法 plus()。但是一個類(class)中最多只能定義一個伴生對象录平。

2麻车、調(diào)用

使用 companion 關(guān)鍵字修改的對象之后,伴生對象就相當(dāng)于是外部類的對象斗这,我們可以使用類直接調(diào)用动猬,如下:

fun main(args: Array<String>) {

    println(NumberTest.plus(1, 2))  // 3
    println(NumberTest.flag)  // false

}

從上面的代碼可以看出調(diào)用的時候與伴生對象的名稱沒有多大關(guān)系,所以名稱 Obj 可以省略不寫表箭。

3前硫、伴生對象的作用

通過上面的 NumberTest.plus(1, 2)NumberTest.flag 代碼不難看出來拢军,類似于 Java 中使用類訪問靜態(tài)成員的語法。因為 Kotlin 取消了 static 關(guān)鍵字,所以 Kotlin 引入伴生對象來彌補沒有靜態(tài)成員的不足猪半。可見涵亏,伴生對象的主要作用就是為其所在的外部類模擬靜態(tài)成員晰韵。

4、與 Java 代碼共存

知道了伴生對象的特點之后拆魏,那么我們?nèi)绾闻c Java 代碼共存呢盯桦?也就是如何在 Java 代碼中調(diào)用 Kotlin 的伴生對象呢慈俯?如下:

public class NumberJavaTest {

    public static void main(String[] args) {
        System.out.println(NumberTest.Obj.plus(2, 3)); // 5
        // System.out.println(NumberTest.Companion.plus(2, 3));
        NumberTest.Obj.setFlag(true);
        // NumberTest.Companion.setFlag(true);
        System.out.println(NumberTest.Obj.getFlag()); // true
        // System.out.println(NumberTest.Companion.getFlag());
    }

}
  • 如果聲明伴生對象有名稱,則使用:
類名.伴生對象名.方法名()
類名.半生對象名.屬性的setter,getter方法

例:NumberTest.Obj.plus(2, 3)
  • 如果聲明伴生對象無名稱俺附,則采用 Companion 關(guān)鍵字調(diào)用:
類名.Companion.方法名()
類名.Companion.屬性的setter,getter方法

例:NumberTest.Companion.getFlag()

5肥卡、@JvmField 和 @JvmStatic 的使用

在上面的例子中,我們知道了可以在 Java 代碼中調(diào)用 Kotlin 中伴生對象的成員事镣,類似于 Java 類中的靜態(tài)成員步鉴。但是看上去和 Java 中的還是略有區(qū)別,因為類名和方法名/屬性setter,getter方法名之間多了個伴生對象的名稱或者 Companion 關(guān)鍵字璃哟。如何使其在調(diào)用的時候與 Java 中的調(diào)用看上去一樣呢氛琢?

Kotlin 為我們提供了 @JvmField@JvmStatic 兩個注解。@JvmField 使用在屬性上随闪,@JvmStatic 使用在方法上阳似。如:

class NumberTest {
    companion object {
        @JvmField
        var flag = false

        @JvmStatic
        fun plus(num1: Int, num2: Int): Int {
            return num1 + num2
        }
    }
}

這樣我們在 Java 代碼中調(diào)用的時候就和 Java 類調(diào)用靜態(tài)成員的形式一致了,Kotlin 代碼調(diào)用方式不變:

 public static void main(String[] args) {
        System.out.println(NumberTest.plus(2, 3));
        NumberTest.flag = true;
        System.out.println(NumberTest.flag);
}

6铐伴、const 關(guān)鍵字

在伴生對象中撮奏,我們可能需要聲明一個常量,目的是等同于 Java 中的靜態(tài)常量当宴。有兩種方式畜吊,一種是上面所提到的使用 @JvmField 注解,另一種則是使用 const 關(guān)鍵字修飾户矢。這兩種聲明方式都等同于 Java 中 static final 所修飾的變量玲献。如下代碼:

companion object {
      const val m = 2

      @JvmField
      val n = 3
}

// java 代碼中調(diào)用:
System.out.println(NumberTest.m);
System.out.println(NumberTest.n);

如果不使用 const 修飾的常量,我們需要引用伴生對象來調(diào)用梯浪,而且必須調(diào)用 getter 方法捌年。

companion object {
      const val k = 2
}

// java 代碼中調(diào)用:
System.out.println(NumberTest.Companion.getK());

而以上 const 關(guān)鍵字使用的影響只是在 Java 中調(diào)用方式不同,在 Kotlin 中并無影響挂洛。

三礼预、伴生對象的擴展

如果了解 Kotlin 的話,應(yīng)該知道在 Kotlin 中抹锄,對象時可以被擴展的逆瑞。在 Kotlin 中,如果類中包含伴生對象伙单,則 Kotlin 允許伴生對象擴展方法和屬性获高。也就是為伴生對象所在的外部類擴展靜態(tài)成員,訪問方式一致吻育。

接著上面的列子念秧,為上面的 NumberTest 類擴展一個 minus 方法:

1、擴展方法

fun NumberTest.Companion.minus(str: String): Int {
    if (str != null && str.isNotEmpty()) {
        return try {
            str.toInt()
        } catch (e: Exception) {
            0
        }
    }
    return 0
}

通過例子我們看出布疼,我們可以通過類名去擴展方法摊趾,如果伴生對象有名稱的話币狠,使用 類名.伴生對象名.方法名()來擴展,否則使用 類名.Companion.方法名()來擴展即可砾层。

2漩绵、擴展屬性

var NumberTest.Companion.number
    get() = 3
    set(value) {
        // set 方法并沒有 field 可以用來存儲 value
        this.plus(value, 2)
    }

val NumberTest.Companion.str
    get() = "這是一個擴展屬性"

同樣,我們也可以擴展屬性肛炮,但是擴展屬性有以下幾個特點:

  • 擴展屬性不能有初始值止吐,沒有 field 來存儲屬性值;
  • 擴展屬性因為沒字段來存儲值侨糟,所以為計算屬性碍扔;
  • 擴展 var 屬性必須提供 setter 和 getter 方法,擴展 val 屬性必須提供 getter 屬性秕重。

四不同、總結(jié)

先來個小插曲,回歸到本文前言溶耘,定義在 Activity 中的啟動方法二拐,用到伴生對象可以寫成如下格式:

 companion object {
        const val EXTRA_PARAMS = "extra_params"

        fun open(context: Context, params: String) {
            var intent = Intent(context, TestActivity::class.java)
            intent.putExtra(EXTRA_PARAMS, params)
            context.startActivity(intent)
        }
    }
  • 每個類可以最多有一個半生對象;
  • 伴生對象的成員類似于 Java 的靜態(tài)成員凳兵;
  • 使用 const 關(guān)鍵字修飾常量卓鹿,類似于 Java 中的 static final修飾。
  • 可以使用 @JvmField 和 @JvmStatic 類似于 Java 中調(diào)用靜態(tài)屬性和靜態(tài)方法留荔;
  • 伴生對象可以擴展屬性和擴展方法。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末澜倦,一起剝皮案震驚了整個濱河市聚蝶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌藻治,老刑警劉巖碘勉,帶你破解...
    沈念sama閱讀 212,686評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異桩卵,居然都是意外死亡验靡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,668評論 3 385
  • 文/潘曉璐 我一進店門雏节,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胜嗓,“玉大人,你說我怎么就攤上這事钩乍〈侵荩” “怎么了?”我有些...
    開封第一講書人閱讀 158,160評論 0 348
  • 文/不壞的土叔 我叫張陵寥粹,是天一觀的道長变过。 經(jīng)常有香客問我埃元,道長,這世上最難降的妖魔是什么媚狰? 我笑而不...
    開封第一講書人閱讀 56,736評論 1 284
  • 正文 為了忘掉前任岛杀,我火速辦了婚禮,結(jié)果婚禮上崭孤,老公的妹妹穿的比我還像新娘类嗤。我一直安慰自己,他們只是感情好裳瘪,可當(dāng)我...
    茶點故事閱讀 65,847評論 6 386
  • 文/花漫 我一把揭開白布土浸。 她就那樣靜靜地躺著,像睡著了一般彭羹。 火紅的嫁衣襯著肌膚如雪黄伊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,043評論 1 291
  • 那天派殷,我揣著相機與錄音还最,去河邊找鬼。 笑死毡惜,一個胖子當(dāng)著我的面吹牛拓轻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播经伙,決...
    沈念sama閱讀 39,129評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼扶叉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了帕膜?” 一聲冷哼從身側(cè)響起枣氧,我...
    開封第一講書人閱讀 37,872評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎垮刹,沒想到半個月后达吞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,318評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡荒典,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,645評論 2 327
  • 正文 我和宋清朗相戀三年酪劫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寺董。...
    茶點故事閱讀 38,777評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡覆糟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出遮咖,到底是詐尸還是另有隱情搪桂,我是刑警寧澤,帶...
    沈念sama閱讀 34,470評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站踢械,受9級特大地震影響酗电,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜内列,卻給世界環(huán)境...
    茶點故事閱讀 40,126評論 3 317
  • 文/蒙蒙 一撵术、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧话瞧,春花似錦嫩与、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,861評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至埃篓,卻和暖如春处坪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背架专。 一陣腳步聲響...
    開封第一講書人閱讀 32,095評論 1 267
  • 我被黑心中介騙來泰國打工同窘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人部脚。 一個月前我還...
    沈念sama閱讀 46,589評論 2 362
  • 正文 我出身青樓想邦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親委刘。 傳聞我的和親對象是個殘疾皇子丧没,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,687評論 2 351