Kotlin——伴生对象

学习kotlin是上个月的事了,自己当时也没有记笔记,发现等开始写项目的时候又不会用了。所以对一些模糊的点,比较难的点还是总结一下,加深印象,还利于后面复习。

伴生对象:工厂方法和静态成员

这个是从来没有在java中有的一个概念。

Kotlin中的类不能拥有静态成员。java的static关键字并不是kotlin语言的一部分。可以替代的是kotlin中依赖包级别函数和对象声明。大多数情况下,推荐顶层函数。但是顶层函数不能访问类的private成员,因此当我们需要写一个可以在没有类实例的情况下调用但是需要访问类内部的函数,可以将其写成需要类中的对象声明的成员。就想到了静态工厂方法。

类内部的对象声明可以用companion关键字标记。这样就获得了直接通过容器类名称来访问这个对象的方法和属性的能力。不需要显示地指明对象的名称。看起来很像java中的静态方法调用。例子如下:

class MyClass{
    companion object Factory{
        fun create():MyClass = MyClass()
    }
}

该伴生对象的成员可通过只使用类名作为限定符来调用:

val instance = MyClass.create()
//等价于
val instance = MyClass.Factory.create()

可以省略伴生对象的名称,在这种情况下将使用名称:Companion:

class MyClass{
    companion object{ }
}
val x = MyClass.Companion

其自身所用的类的名称可用作该类的伴生对象的引用:

class MyClass1{
    companion object Named{ }
}
val x = MyClass1

class MyClass2{
    companion object{ }
}
val y = MyClass2

伴生对象的成员虽然看起来像其他语言的静态成员,在运行时他们仍然是真实对象的实例成员,而且还可以实现如下的接口:

interface Factory<T>{
    fun create():T
}

class MyClass{
    companion object : Factory<MyClass>{
        override fun create():MyClass = MyClass()
        
        var name = "default"
        val myClass = MyClass()
        fun sayClass(){
            print("hello say")
        }
    }
}

fun main(arg:Array<String>){
    val f:Factory<MyClass> = MyClass
}

刚开始单看这段代码获取有些云里雾里的,不如就把它转换成我们最为熟悉的java代码去看看,就会一目了然了。编译器自带的工具很好用。

//Factory接口
public interface Factory {
   Object create();
}

public final class MyClass {
   @NotNull
   private static String name = "default";
   @NotNull
   private static final MyClass myClass = new MyClass();
    //伴生对象在外部类中被定义为静态字段且不可修改
   public static final MyClass.Companion Companion = new MyClass.Companion((DefaultConstructorMarker)null);
    
    //没有定义伴生对象的名字默认为Companion
    public static final class Companion implements Factory {
      @NotNull
      public MyClass create() {
         return new MyClass();
      }

      // $FF: synthetic method
      // $FF: bridge method
      public Object create() {
         return this.create();
      }

      private Companion() {
      }

      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
      
      @NotNull
      public final String getName() {
         return MyClass.name;
      }

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

      @NotNull
      public final MyClass getMyClass() {
         return MyClass.myClass;
      }

      public final void sayClass() {
         String var1 = "hello say";
         System.out.print(var1);
      }
   }  
}

public final class TestKt {
   public static final void main(@NotNull String[] arg) {
      Intrinsics.checkParameterIsNotNull(arg, "arg");
      //实例化MyClass对象的时候本质是MyClass.Companion
      Factory f = (Factory)MyClass.Companion;
   }
}

从kotlin代码编译为java代码后可以知道:

  • 使用伴生对象实际上是在这个类内部创建了一个名为 Companion的静态单例内部类
  • 伴生对象中定义的属性会直接编译为外部类的私有静态字段,var和val的区别就是无有final
  • 函数会被编译为伴生对象的方法

在jvm平台,如果使用@JvmStatic注解,你可以将伴生对象的成员生成为真正的静态方法和字段。

伴生对象的扩展

如果一个类定义有一个伴生对象,也可以为伴生对象定义扩展函数与属性,就像伴生对象的常规成员一样,可以只使用类名作为限定符来调用伴生对象的扩展成员:

class MyClass{
    companion object{ }
}

fun MyClass.Companion.printCompanion(){
    print("companion")
}

fun main(){
    MyClass.printCompanion()
}

伴生对象在工厂方法中的应用

在学习kotlin中最大的感受就是语法简单了很多,很多东西都可以代替java,但是其实和java的区别也比较大,要理解其中的原理先去学习每种语法在平常写代码的时候可以在哪些地方使用。

伴生对象可以访问类中的所有private,包括private构造方法,它是实现工厂模式的理想选择。

简单来说,在平常的开发中我们创建一个对象,因为不同的参数就会写很多个不同参数的构造方法。在构造方法很多的情况下我们就需要查api,看每个参数对应的含义是什么。因此为了解决这种情况,我们根据不同情况把创建对象包装起来,调用根据此功能命名的方法。代码如下:

  • 定义一个拥有多个从构造方法的类

class User{

    val nickName : String
    
    constructor(name:String){
        nickName = name
    }
    
    constructor(qqEmail:String){
        nickName = getNameFromQq(qqEmail)
    }
    
    constructor(weChact:String){
        nickName = getNameFromWechat(weChat)
    }
}

这里的功能就是在创建用户昵称的时候,根据不同的登录方式在本地进行处理,生成新的用户名。

  • 使用工厂方法来代替从构造方法

//主构造方法标记为私有
class User private constructor(val nickName:String){
    companion object{
        fun createNameFromLocal(name:String){
            User(name)
        }
        
        fun createNameFromQq(qqEmail:String){
            User(getNameFromQq(qqEmail))
        }
        
        fun createNameFromWechat(weChact:String){
            User(getNameFromWechat(weChat))
        }
    }
}

现在就可以通过用途来创建不同的用户。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kotlin中,每个类都可以有一个伴生对象伴生对象是与类绑定在一起的对象,可以访问类的所有成员,包括私有成员。伴生对象可以访问类的私有构造函数和属性,因此可以用来实现工厂方法。下面详细讲解Kotlin伴生对象的使用。 ### 创建伴生对象Kotlin中,我们使用`companion object`关键字来创建伴生对象伴生对象可以有一个可选的名称,如果没有指定名称,则默认名称为`Companion`。 ```kotlin class MyClass { companion object { // ... } } ``` ### 访问伴生对象 我们可以通过类名来访问伴生对象的成员,就像访问静态成员一样。 ```kotlin MyClass.Companion.someMethod() ``` 或者,我们可以省略`Companion`名称。 ```kotlin MyClass.someMethod() ``` ### 伴生对象的初始化 伴生对象可以拥有自己的初始化代码块,就像类一样。 ```kotlin class MyClass { companion object { init { // 初始化代码 } } } ``` ### 使用伴生对象实现工厂方法 伴生对象常用于实现工厂方法。我们可以在伴生对象中定义一个工厂方法来创建类的实例。 ```kotlin class MyClass private constructor(val value: Int) { companion object { fun create(): MyClass { return MyClass(42) } } } ``` 在上面的例子中,我们定义了一个私有构造函数,然后在伴生对象中定义了一个工厂方法`create()`来创建类的实例。由于构造函数是私有的,因此不能直接使用`MyClass()`来创建类的实例,只能通过`MyClass.create()`来创建类的实例。 ### 伴生对象的扩展 我们可以在伴生对象中定义扩展函数,就像在类中定义扩展函数一样。 ```kotlin class MyClass { companion object { fun create(): MyClass { return MyClass(42) } } } fun MyClass.Companion.someExtension() { // ... } ``` 上面的代码中,我们在伴生对象中定义了一个工厂方法`create()`和一个扩展函数`someExtension()`。我们可以通过类名来调用这些方法,例如`MyClass.create()`和`MyClass.someExtension()`。 ### 总结 Kotlin中的伴生对象是与类绑定在一起的对象,可以访问类的所有成员,包括私有成员。伴生对象可以用于实现工厂方法、定义扩展函数等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值