轉(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)方法留荔;
- 伴生對象可以擴展屬性和擴展方法。