Kotlin|浅谈Kotlin静态变量实现那些事

文章主要是针对Kotlin中静态变量的实现方式进行比较以及在java和kotlin编程环境下的差异
对于Kotlin使用方式上一视同仁,对于java就需要额外注意调用方式

一.Kotlin实现静态变量的总览

   class Demo3 {
    companion object {
        //第一种方式
        val FIRST_WAY = "first_way"

        //第二种方式
        const val SECOND_WAY = "second_way"

        //第三种方式
        @JvmStatic
        val THIRD_WAY = "third_way"

        //第四种方式
        @JvmField
        val FOURTH_WAY = "fource_way"
    }
}
复制代码

对于Kotlin而言,直接调用Demo3.XXX_WAY就可以简单实现静态变量的引用,但是本文从java的角度去分析这四种方式的不同之处,加深对这四种编写方式的理解

二.第一种方式

val FIRST_WAY = "first_way"

反编译下成Java代码看下:

public final class Demo3 {
   @NotNull
   private static final String FIRST_WAY = "first_way";
   
   @NotNull
   public static final Demo3.Companion Companion = new Demo3.Companion((DefaultConstructorMarker)null);

   public static final class Companion {
      @NotNull
      public final String getFIRST_WAY() {
         return Demo3.FIRST_WAY;
      }
   }
}
复制代码
  1. val修饰的变量本质上在Demo3类中声明了一个私有变量,只不过在伴生类中kotlin生成了一个方法getFIRST_WAY
  2. 在java中我们就只能借助于伴生对象类获取到该静态变量:Demo3.Companion.getFIRST_WAY()
  3. 在kotlin中就可以简单通过Demo3.FIRST_WAY简单调用,反编译这句调用代码: Demo3.Companion.getFIRST_WAY();
  4. 可以看到和java的调用方式一样,只不过kotlin帮助我们做了封装,隐藏了部分细节,实现更加简单的调用

三.第二种方式

const val SECOND_WAY = "second_way"

反编译成java代码:

public final class Demo3 {
   @NotNull
   public static final String SECOND_WAY = "second_way";
   @NotNull
   public static final Demo3.Companion Companion = new Demo3.Companion((DefaultConstructorMarker)null);

   public static final class Companion {
   }
}
复制代码
  1. 通过这种方式声明的静态变量是定义在Demo3类中公有的属性,和java中定义的公有的静态变量一模一样,获取方式与Companion伴生对象无关,所以java中调用该变量的方式和kotlin的调用方式一模一样
  2. 使用const val需要注意这种方式有两个限制:
  • 赋值的value必须是常量
  • 属性的类型必须是String和基本包装类型,比如Int、Long、Float等

四.第三种方式

@JvmStatic val THIRD_WAY = "third_way"

反编译下:

public final class Demo3 {
   @NotNull
   private static final String THIRD_WAY = "third_way";
   @NotNull
   public static final Demo3.Companion Companion = new Demo3.Companion((DefaultConstructorMarker)null);

   @NotNull
   public static final String getTHIRD_WAY() {
      Demo3.Companion var10000 = Companion;
      return THIRD_WAY;
   }

   public static final class Companion {
      @NotNull
      public final String getTHIRD_WAY() {
         return Demo3.THIRD_WAY;
      }
   }
}

复制代码
  1. 可以看到其实这种方式就是在第一种方式的基础上,在Demo3类中增加了获取该静态变量的静态公有方法,所以在java中比第一种方式多提供了一种调用方式:
  • Demo3.Companion.getFIRST_WAY()(第一种方式)
  • Demo3.getFIRST_WAY()(增加的)
  1. 总体而言不推荐这种方式来声明一个静态变量

五.第四种方式

@JvmField val FOURTH_WAY = "fource_way"

@JvmField注解可以简单理解为保留变量声明时指定的访问修饰符:

  • kotlin中普通的val和var修饰的属性会被默认设置为private类型,并自动帮助我们生成对应属性的set或者get访问方法,我们指定属性的访问修饰符时其实指定的是其生成的set或者get方法的访问修饰符,而不是变量的访问修饰符,变量最终还是private
  • 当给这些属性加上@JvmField注解时,那么当我们指定属性访问的属性修饰符类型的是什么最终就是什么

反编译下代码:

public final class Demo3 {
   @JvmField
   @NotNull
   public static final String FOURTH_WAY = "fource_way";
   @NotNull
   public static final Demo3.Companion Companion = new Demo3.Companion((DefaultConstructorMarker)null);

   public static final class Companion {
      private Companion() {
      }
   }
}

复制代码
  1. 可以从代码中看到,和第二种方式const val的实现方式一模一样,所以调用方式上java和kotlin也是一模一样的
  2. 和第二种方式最大的区别就是:没有第二种方式的限制—属性类型可以任意且赋值的value也任意,不限于常量
  3. 获取方式和伴生类对象Companion没有任何关系
  4. 当const val不满足的话,强烈推荐这种方式

六.总结

  1. 第一种方式和第三种方式依赖于伴生对象获取静态变量,不是特别推荐
  2. 第二种方式和第四种方式属于比较推荐的方式,优先使用第二种,当第二种不满足的时候采用第四种
  3. @JvmStatic比较适合修饰方法,伴生对象和object声明的单例中方法其实都不是静态方法,一般常用的方式就是通过该注解实现真正的静态方法
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享