【Kotlin】object使用

文章介绍了Kotlin如何用伴生对象替代Java中的static关键字,以及伴生对象如何实现单例模式。此外,还提到了object表达式在简化匿名内部类,如点击监听器时的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

static 去哪了

在我学 Kotlin 第一天的时候就发现了一个问题,我们学习 Java 的时候,第一个示例输出Hello world的时候,main方法总是会被public static void 修饰着,而 Kotlin只需要简单的 fun main(),前面的我们知道 void 在 Kotlin 中可以用 Uint取代,那么static,Kotlin 使用什么魔法呢? 那就是object,他可以完美的代替static,下面我们来了解一下object。

伴生对象

按照惯例,我们还是从代码开始

public class People {
    private String name;
    private int age;
    private int sex;

    public People(String name, int age, int sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    static boolean isMale(People people) {
        return people.sex == SEX_MALE;
    }

    static int SEX_MALE = 0;
    static int SEX_FEMALE = 1;


    public static void main(String[] args) {
        People people = new People("lihong", 12, People.SEX_FEMALE);
        System.out.println(People.isMale(people));
    }
}

上面的代码在 Java 中比较常见,当然也有可能存在包装一个工具类来判断性别等等。但是总得来说,如果我们细看上面的代码,我们发现,这个类中,即有静态变量,也有静态方法,还有普通变量以及普通方法。放在一个类中,感觉挺混乱的。因为静态变量静态方法是属于这个类的,普通变量,普通方法是属于一个对象的。在 Kotlin 中为了让这种结构清晰,于是就引入了伴生对象。而伴生对象其实就是相对于这个类来说的。意思就是伴随这个类的对象。当类被加载的时候,就会初始化。而这里和 static 修饰的对象不谋而合。那么上面的代码使用 Kotlin 中伴生对象的方式来写,就是下面的代码:

class People(var name: String, var age: Int, val sex: Int) {
    companion object {
        val SEX_MALE = 0
        val SEX_FEMALE = 1

        fun isMale(people: People): Boolean {
            return people.sex == SEX_MALE
        }
    }
}

fun main() {
    val people = People("lihua", 12, People.SEX_FEMALE)
    println(People.isMale(people))
}

我们再看下反编译后的代码

public final class People {
   @NotNull
   private String name;
   private int age;
   private final int sex;
   private static final int SEX_MALE;
   private static final int SEX_FEMALE = 1;
   @NotNull
   public static final Companion Companion = new Companion((DefaultConstructorMarker)null);

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

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

   public final int getAge() {
      return this.age;
   }

   public final void setAge(int var1) {
      this.age = var1;
   }

   public final int getSex() {
      return this.sex;
   }

   public People(@NotNull String name, int age, int sex) {
      Intrinsics.checkNotNullParameter(name, "name");
      super();
      this.name = name;
      this.age = age;
      this.sex = sex;
   }

   public static final class Companion {
      public final int getSEX_MALE() {
         return People.SEX_MALE;
      }

      public final int getSEX_FEMALE() {
         return People.SEX_FEMALE;
      }

      public final boolean isMale(@NotNull People people) {
         Intrinsics.checkNotNullParameter(people, "people");
         return people.getSex() == ((Companion)this).getSEX_MALE();
      }

      private Companion() {
      }

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

public final class PeopleKt {
   public static final void main() {
      People people = new People("lihua", 12, People.Companion.getSEX_FEMALE());
      boolean var1 = People.Companion.isMale(people);
      System.out.println(var1);
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }
}

反编译后的代码我们看到,其实 companion object 修饰的部分,被编译撑了一个静态内部类,类名就是Companion。里面有两个get 方法,还有一个就是我们自己写的isMale方法,最后输出的也是 Companion 对象里面的返回值。所以可以看成,伴生对象就是用来替代 static 的一直方式。一个类的伴生对象全局只能有一个,因为反编译我们看到了其实就是一个静态类。所以这个我们很容易就想到了一种设计模式–单例模式。

Kotlin 单例

没错,上面我们了解到一个类的伴生对象全局只有一个,使用 companion object 修饰,自然而然的想到单例模式,Kotlin 的单例没错就是使用 object,我们看下 Kotlin 怎么创建一个单例的,我们以封装 LogUtil为例:

object LogUtil{
    val packageName:String = "com.onexiao.log"
    var tag:String = "TAG"
    
    fun error(message:String){
        println("[PKG]: $packageName , [MSG] $message")
    }
    ...
}

反编译后我们看到,这里的单例模式其实就是饿汉式的,这里就不详细展开说明各种单例的创建方式,因为只是讲object 作用,所以仅说明一般场景的单例。

public final class LogUtil {
   @NotNull
   private static final String packageName;
   @NotNull
   private static String tag;
   @NotNull
   public static final LogUtil INSTANCE;

   @NotNull
   public final String getPackageName() {
      return packageName;
   }

   @NotNull
   public final String getTag() {
      return tag;
   }

   public final void setTag(@NotNull String var1) {
      Intrinsics.checkNotNullParameter(var1, "<set-?>");
      tag = var1;
   }

   public final void error(@NotNull String message) {
      Intrinsics.checkNotNullParameter(message, "message");
      String var2 = "[PKG]: " + packageName + " , [MSG] " + message;
      System.out.println(var2);
   }

   private LogUtil() {
   }

   static {
      LogUtil var0 = new LogUtil();
      INSTANCE = var0;
      packageName = "com.onexiao.log";
      tag = "TAG";
   }
}

object 表达式

作为Android 开发人员,对于各种 click 监听的写法可谓是深恶痛绝,匿名内部类在 Java 的写法也是,如今支持了 lambda 表达式还好,在 Kotlin 中,如果使用匿名内部类的方式,可以使用 object 表达式方式来,我们以 Android 常见的设置监听的方式

val clickListener = object :OnClickListener{
    override fun onClick(v: View?) {
        // TODO("Not yet implemented")
    }
}
mft.setOnClickListener(clickListener)

当然这里仅仅举一个例子来说,如果真的想要简洁方式的话,直接使用 lambda 表达式,会更加简洁,这里只是用来说明 object 表达式,可以很好的将内部类代替。这里说明一下,如果匿名内部类里面的方法较多,比较适合使用 object 表达式,而方法只有一个的话,推荐使用 Lamba 表达式

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0neXiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值