kotlin - 實現(xiàn)靜態(tài)的幾種方式詳解

將 kotlin 編譯成 java

先來個題外話,我們?nèi)绾慰?kotlin 對應的 java 代碼,kotlin 最終還是要編譯成 java class 在 JVM 上運行的,有時我們的確是想看看用 kotlin 寫完的代碼編譯完了是什么樣子,這樣有助于我們理解 kotlin 語法

其實很簡單,AS tools 工具里面有提供

  1. tools -> Show kotlin Bytecode


  2. 點擊 Decompile


ok ,這樣就行了


kotlin 實現(xiàn)靜態(tài)的方式

在 kotin 語言中其實沒有 java static 的這個概念,基本都是用一個靜態(tài)對象來模擬 class 的靜態(tài)屬性和方法,目前有4種實現(xiàn)方式:

  • companion object - 伴隨對象,聲明單例的方式
  • @JvmField + @JvmStatic 注解 - 使用注解標簽聲明 static 的部分
  • object 單例 - 靜態(tài)單例其實和 companion object 類似
  • const - 包內(nèi)唯一性,脫離類的束縛,kotlin 的特性,在 java 中會編譯生成一個 kotlin.kt 的文件專門對齊提供支持

companion object

companion object 伴隨對象這是我們在 kotlin 中最常用的方式了吧,在 companion object 里面我們即可以聲明屬性,也可以聲明方法,kotlin 中的調(diào)用方式感覺和 java 的 static 一樣,舉個例子看下面:

class BookKotlin {

    var name: String = "AA"

    fun speak() {}

    companion object instance {

        var nameStatic: String = "BB"

        fun speakStatic() {}

    }
}

kotlin 中使用如下:

kotlin 中調(diào)用靜態(tài)方法和屬性

kotlin 中調(diào)用成員方法和屬性

看上面圖,我們在 kotlin 中使用時感覺的確是和 java 中的 static 一樣,靜態(tài)參數(shù)方法和成員參數(shù)方法能有效區(qū)別開來,下面我們來看看 java 中使用

java 中使用如下:

類名. 沒有靜態(tài)屬性和方法,只有一個靜態(tài)對象
這個靜態(tài)對象下我們可以找到我們聲明的靜態(tài)屬性和方法
new 一個對象我們可以使用成員變量和方法

kotlin 的使用 ok ,但是一到 java 上就全變了,為啥,因為 kotlin 最終也是會編譯成 java 文件去 JVM 運行的,kotlin 并沒有提供自己特有的 VM ,所以kotlin 代碼還是要轉(zhuǎn)換成 java 代碼的,要不 kotlin 怎么宣傳 kotlin 和 java 可以實現(xiàn)無縫調(diào)用

kotlin 中所有的成員變量,不管是不是 static 的都有 get/set 方法,另外 kotlin 并沒有把我們聲明的靜態(tài)參數(shù)和方法聲明成 static 的,而是通過 instance 這個靜態(tài)對象中轉(zhuǎn)使用的,這就讓我們迷惑了,kotlin 變成成 java 之后到底上啥樣的,會不會和我們的初衷不同,影響我們使用

instance 這個靜態(tài)對象的名字是采用 companion object 后面跟的名字,可以不寫,不寫的話默認就是 INSTANCE(版本不同會有變化)

下面我們把 kotlin 轉(zhuǎn)換成 java 代碼來一探究竟

把 kotlin 代碼轉(zhuǎn)成 java:

public final class BookKotlin {

   private static String nameStatic = "BB";

   public static final BookKotlin.instance instance = new BookKotlin.instance((DefaultConstructorMarker)null);

   private String name = "AA";

   public final String getName() {
      return this.name;
   }

   public final void setName(@NotNull String var1) {
      Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
      this.name = var1;
   }

   public final void speak() {
   }

   public static final class instance {
      @NotNull
      public final String getNameStatic() {
         return BookKotlin.nameStatic;
      }

      public final void setNameStatic(@NotNull String var1) {
         Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
         BookKotlin.nameStatic = var1;
      }

      public final void speakStatic() {
      }

      private instance() {
      }

      // $FF: synthetic method
      public instance(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}

看到 java 代碼后,大家都徹底清楚了吧, companion object 伴隨對象真不是白叫的,真的是個對象,在 class 內(nèi)部添加一個 static final class 的靜態(tài)內(nèi)部類實現(xiàn)對象來模擬 static 特性


@JvmField + @JvmStatic 注解

上面我們見識了 companion object 伴隨對象,那么 kotlin 是不是真的無法實現(xiàn) static 了,也不是,kotlin 還是提供了相關辦法,這就是 @JvmField + @JvmStatic 注解,其意思是聲明成員和方法使用 JVM 提供的特性

  • @JvmField - 修飾靜態(tài)變量
  • @JvmStatic - 修飾靜態(tài)方法
  • @JvmField@JvmStatic 只能寫在 object 修飾的類或者 companion object 里,寫法雖然有些別扭,但是效果是真的是按 static 來實現(xiàn)的

我們把上面的代碼修改下:

class BookKotlin {

    companion object {

        @JvmField
        var nameStatic: String = "BB"

        @JvmStatic
        fun speakStatic() {
        }
    }

    var name: String = "AA"

    fun speak() {}
}

kotlin 中使用如下:

java 中使用如下:

把 kotlin 代碼轉(zhuǎn)成 java:

public final class BookKotlin {

   @JvmField
   public static String nameStatic = "BB";

   @JvmStatic
   public static final void speakStatic() {
      Companion.speakStatic();
   }

   public static final BookKotlin.Companion Companion = new BookKotlin.Companion((DefaultConstructorMarker)null);

   private String name = "AA";

   @NotNull
   public final String getName() {
      return this.name;
   }

   public final void setName(@NotNull String var1) {
      Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
      this.name = var1;
   }

   public final void speak() {
   }


   public static final class Companion {
      @JvmStatic
      public final void speakStatic() {
      }

      private Companion() {
      }

      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}


object 單例

kotlin 自身提供了一種單例實現(xiàn)方式:object ,直接用來修飾 class ,用 object 修飾的類不能 new 對象,只能使用 object 提供的單例

object BookKotlin {

    var name: String = "AA"

    fun speak() {}
}

kotlin 中使用如下:

object 修飾的類不能創(chuàng)建對象了

java 中使用如下:

把 kotlin 代碼轉(zhuǎn)成 java:

public final class BookKotlin {

   private static String name;
   public static final BookKotlin INSTANCE;

   public final String getName() {
      return name;
   }

   public final void setName(@NotNull String var1) {
      Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
      name = var1;
   }

   public final void speak() {
   }

   static {
      BookKotlin var0 = new BookKotlin();
      INSTANCE = var0;
      name = "AA";
   }
}

雖然 name 是 static 的了,但還是 private 私有的,還是得通過靜態(tài)單例來中轉(zhuǎn)調(diào)用,真的是單例


const

const 寫在 class 外面,效果 = @JvmField,但是不能修飾方法,也不能和 @JvmField 混用,一般就是用來聲明常用值的,用處不多,而且只能用 val ,var 不行,想要修飾方法的話,不寫 const 就行

const val name: String = "AA"
fun adk(){}
class BookKotlin {

    fun speak() {}
}

kotlin 中使用如下:
kotlin 沒有包的概念,所以直接用,注意這么寫其實已經(jīng)相當于脫離了類的范圍,一個包的范圍內(nèi)不能重名的

java 中使用如下:


這個 BookKotlinKt 文件就是為了專門支持這個 kotlin 特性而生成的輔助類,java 中我們是通過這個類來調(diào)用 const 聲明的內(nèi)容的,為啥要有這個類呢,因為 java 是有包這個概念的,所有的文件必須要有統(tǒng)一的地址規(guī)范,所以 kotlin 層面只能是提供 XXXKt 文件來單獨支持了,其實這已經(jīng)脫離了 java 范圍

把 kotlin 代碼轉(zhuǎn)成 java:

public final class BookKotlin {
   public final void speak() {
   }
}

public final class BookKotlinKt {
   @NotNull
   public static final String name = "AA";

   public static final void adk() {
   }
}

在 java 代碼中是以 kotlin 輔助類存在的,這樣用的人真的是非常少,限制太大

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容