static修飾符是java里面非常常用的一個東西博个,用法也非常多怀樟。然而,在kotlin里竟然沒有這個東西盆佣!那該如何替代呢往堡?本文就總結(jié)了下java里面static的幾種常見用法在kotlin里的替代方式。
static在java里面的用法總結(jié)
static在java里面的用法有很多共耍,最常用的有下面幾種:
- 靜態(tài)變量及方法
- 靜態(tài)初始化
- 靜態(tài)內(nèi)部類
下面我們就看看這幾種場景在kotlin是如何實現(xiàn)的投蝉。
場景一:靜態(tài)變量及方法
靜態(tài)變量及方法可能是我們平時用到static最多的地方,我們先看看java里面是如何做的征堪。
java靜態(tài)變量及方法介紹:
首先瘩缆,是靜態(tài)變量和方法的定義:
public class StaticTest {
public static int STATIC_VAR = 0;
public static void staticMethod(String str){
System.out.println(str);
}
}
然后是靜態(tài)變量和方法的使用:
StaticTest.STATIC_VAR = 10;
StaticTest.staticMethod("hello");
java的實現(xiàn)方式大家都非常熟悉了,下面著重說說kotlin是如何實現(xiàn)的佃蚜。
kotlin替代靜態(tài)變量及方法的方案
kotlin通過引入“伴生對象”的概念來替代java里的靜態(tài)變量及方法庸娱。
“伴生對象”這個名詞聽上去很古怪,其實非常簡單:在類的內(nèi)容使用companion
來標記一個對象谐算。所有需要“靜態(tài)化”的變量和方法都放在這個對象里熟尉。
下面是定義伴生對象的代碼:
class StaticTest {
companion object{//伴生對象是可以指定名字的,不過一般都省略掉洲脂。
var STATIC_VAR = 0
fun staticMethod(str: String?) {
println(str)
}
}
}
接下來看看如何使用伴生對象斤儿,伴生對象只能通過類名來訪問,使用方法和java差不多:
StaticTest.STATIC_VAR = 100
StaticTest.staticMethod("hello")
kotlin的伴生對象解決了什么問題恐锦?
大家可能會好奇往果,為什么kotlin要用這么一個奇怪的方式來解決這個問題呢?
我的理解是有兩個原因:
第一一铅,使用伴生對象體現(xiàn)了kotlin一貫的設計理念:一切都是對象陕贮!伴生對象也是對象!而java的static潘飘,顯然和對象沒有關(guān)系肮之。
第二,伴生對象解決了java靜態(tài)變量及方法的一個常見的反模式:靜態(tài)方法及變量可以通過對象的引用來訪問卜录。
還是拿上面的例子戈擒,java的靜態(tài)變量及方法可以通過類引用和對象引用兩種方法訪問:
//通過類引用訪問
StaticTest.STATIC_VAR = 10;
StaticTest.staticMethod("hello");
//通過對象引用訪問
StaticTest obj = new StaticTest();
obj.STATIC_VAR = 10;
obj.staticMethod("hello");
而通過對象引用訪問靜態(tài)變量及方法,顯然是不合適的艰毒。但是在java里卻沒有辦法從語法層面避免這個問題筐高。
而kotlin的伴生對象只能通過類引用訪問,從語法的層面解決了這個問題:
//使用類引用訪問
StaticTest.STATIC_VAR = 100
StaticTest.staticMethod("hello")
//不能使用對象引用訪問
val obj = StaticTest()
obj.STATIC_VAR = 100 //編譯錯誤
obj.staticMethod("hello") //編譯錯誤
總之,kotlin里每個新的語言特性凯傲,都是為了填補java的某一個坑犬辰。
場景二:靜態(tài)初始化
java里的靜態(tài)初始化可以在類加載的時候初始化一些靜態(tài)變量嗦篱,比如:
public class StaticTest {
public static int STATIC_VAR = 0;
static {
STATIC_VAR = 100;
System.out.println("in static init");
}
public static void main(String[] args) {
System.out.println(StaticTest.STATIC_VAR);
}
}
上面的代碼執(zhí)行結(jié)果如下:
in static init
100
在kotlin里冰单,因為java的靜態(tài)變量及方法都是放在伴生對象里實現(xiàn)的,而伴生對象也是一個普通對象灸促,所以可以通過伴生對象的init方法來實現(xiàn)變量的初始化诫欠,代碼如下:
class StaticTest {
companion object{//伴生對象是可以指定名字的,不過一般都省略掉浴栽。
var STATIC_VAR = 0
init {
STATIC_VAR = 100
println("in companion object init")
}
}
}
執(zhí)行代碼:
println(StaticTest.STATIC_VAR)
結(jié)果如下:
in companion object init
100
可以看到荒叼,kotlin的實現(xiàn)方式要比java的更加一致,既然大家都是對象典鸡,所以都是通過init來初始化的被廓。而java里,非靜態(tài)變量是通過構(gòu)造函數(shù)來初始化的萝玷,而靜態(tài)變量是通過static代碼塊來初始化的嫁乘,兩者很不一致。
場景三:靜態(tài)內(nèi)部類
java的內(nèi)部類有兩種球碉,普通內(nèi)部類和靜態(tài)內(nèi)部類蜓斧。二者的區(qū)別是前者可以訪問外部類的變量,而后者不可以睁冬。同時普通內(nèi)部類會持有外部類的一個引用挎春,靜態(tài)內(nèi)部類則沒有。
public class StaticTest {
private int out = 0;
class InnerClass{
public void InnerClassMethod(){
out = 100; //可以訪問外部類的變量
}
}
static class StaticInnerClass{
public void StaticInnerClassMethod(){
out = 100; //編譯錯誤豆拨,不可以訪問外部類的變量
}
}
}
而kotlin的內(nèi)部類也有兩種:內(nèi)部類和嵌套類直奋。從語法上說,二值的差別就是前者多一個inner修飾符施禾。
下面是和java的比較:
kotlin的內(nèi)部類(使用inner修飾符)相當于java的普通內(nèi)部類帮碰,可以訪問外部變量,同時持有外部對象的引用拾积。
kotlin的嵌套類(沒有inner修飾符)相當于java的靜態(tài)內(nèi)部類殉挽,不可以訪問外部變量
kotlin嵌套類的例子:
class StaticTest {
var out = 0
inner class InnerClass{
fun InnerClassMethod(){
out = 100 //內(nèi)部類可以訪問外部變量
}
}
}
kotlin內(nèi)部類的例子:
class StaticTest {
var out = 0
class InnerClass{
fun InnerClassMethod(){
out = 100 //編譯錯誤,嵌套類不可以訪問外部變量
}
}
}
通過對比拓巧,大家應該很容易的搞清楚kotlin里內(nèi)部類和嵌套類的區(qū)別了斯碌。
總結(jié):
本文的知識點總結(jié)如下:
- java的靜態(tài)變量和方法,在kotlin中使用伴生對象替代
- java的靜態(tài)初始化肛度,在kotlin中使用伴生對象的init替代
- java的靜態(tài)內(nèi)部類傻唾,在kotlin中使用嵌套類來替代
希望本文能對您有所幫助,謝謝!