首页 > 其他分享 >kotlin 伴生对象

kotlin 伴生对象

时间:2023-10-30 09:45:09浏览次数:36  
标签:伴生 对象 kotlin Companion Person User nickname

一、伴生对象的目标

1、java的类中有静态成员或函数但是kotlin中没有静态成员或者函数

2、但是伴生对象依赖包级别的函数和对象声明,可以用来替代java中的静态成员和函数

3、伴生对象的本质是静态的

class User private constructor(val nickname: String) {
    companion object {
        val nameUsers = mutableMapOf<String, User>()
        fun newUser(nickname: String): User {

            if (!nameUsers.containsKey(nickname)) {
                nameUsers.put(nickname, User(nickname))
            }
            return nameUsers.getValue(nickname)
        }
    }
}

如上是对应的伴生对象的实例,如下是这段代码转换成java的类细节

public final class User {
   @NotNull
   public static final User.Companion Companion = new User.Companion((DefaultConstructorMarker)null);
   @NotNull
   private final String nickname;
   @NotNull
   private static final Map nameUsers = (Map)(new LinkedHashMap());

   private User(String nickname) {
      this.nickname = nickname;
   }

   @NotNull
   public final String getNickname() {
      return this.nickname;
   }

   // $FF: synthetic method
   public User(String nickname, DefaultConstructorMarker $constructor_marker) {
      this(nickname);
   }

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

      @NotNull
      public final Map getNameUsers() {
         return User.nameUsers;
      }

      @NotNull
      public final User newUser(@NotNull String nickname) {
         Intrinsics.checkNotNullParameter(nickname, "nickname");
         if (!this.getNameUsers().containsKey(nickname)) {
            this.getNameUsers().put(nickname, new User(nickname, (DefaultConstructorMarker)null));
         }

         return (User)MapsKt.getValue(this.getNameUsers(), nickname);
      }

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

转换成代码比较多,这里使用折叠的方式;具体的细节是:

1、User类中创建了:public static final class Companion 嵌套类。同时在User类中创建累这个Companion的静态属性:public static final User.Companion Companion = new User.Companion((DefaultConstructorMarker)null);

2、kotlin的User类中的伴生对象是匿名的,所以转成java使用的类名是:Companion;如果半生对象是有指定名字,比如:companion object CreateUser {。。。}, 则java中创建的嵌套类的类名则不是Companion而是CreateUser

3、通过1和2的描述则可以知道:在java中调用的kotlin伴生对象则通过User.Companion.newUser(nickname), 如果是非匿名则为User.具体名字.newUser(nickname)

 

二、伴生对象的格式

1、在类中声明

2、companion object +可选对象名字 {......}

3、直接能够伴生对象中的函数:class Person { companion object {。。。。}}, 则可以调用:Person.xxxxx

4、以上三点的例子

class Person(val name: String) {
    companion object Loader{
        fun fromJson(json: String): String {
            return json
        }
    }
}

println(Person.Loader.fromJson("kkaaa"))
println(Person.fromJson("kkaaa"))
/*
打印的结果是:
kkaaa
kkaaa
*/

上面的Loader可以加也可以不加。可以根据自己的需要是否增加伴生对象的名称

 

三、伴生对象实现接口

通过一中对伴生对象的描述,转换为java之后是一个嵌套类,那么说明它也是可以进行继承

interface JsonFactory<T> {
    fun fromJson(json: String): T
}
class Person(val name: String) {
    companion object Loader: JsonFactory<Person>{ // 在伴生对象这里增加r: JsonFactory<Person>,同时实现fromJson函数
        override fun fromJson(json: String): Person { //注意这里有override
            return Person(json)
        }
    }
}

fun <T> loadFromJson(factory: JsonFactory<T>): T {
    return factory.fromJson("kkqqq")
}

loadFromJson(Person) // 这里的调用,直接传入Person; 咱们对companion的调用是Person.fromJson,则是把Person当成对象,所以直接传入Person是可以的

那么在调用loadFromJson函数是否可以传入Person.Loader()? 这里给的报错是:error: not enough information to infer type variable T

 

四、伴生对象扩展

1、类似普通的扩展函数,伴生对象也允许扩展函数。如果类中有伴生对象,那么在外部你可以定义该伴生对象的扩展函数

class Person(val name: String) {
    companion object {} // 这里需要一个伴生对象,即使是空对象否则没法做扩展
}

// 因为上面的半生对象是匿名,所以这里使用默认的Companion
// 如果上面使用非匿名如: companion object Loader {}
// 那么这里就需要使用:Person.Loader.fromJson
fun Person.Companion.fromJson(json: String): Person {
    return Person(json)
}

 

五、对象表达式:匿名内部类

1、object除了能够用来作为伴生对象还能够用来声明匿名对象

2、匿名对象可以实现多个接口或者不实现接口,java的匿名内部类只能扩展一个类或实现一个借口

    val linstener = object: MouseAdapter() { // 这里使用object
        override fun mouseClicked(e: MouseEvent) {。。。} // 这里继承了MouseAdapter
        override fun mouseEntered(e: MouseEvent) {。。。}
    }

如上就是匿名对象的使用方式

3、下面的这个例子是实现接口的匿名对象

    val person = object: Person {
        override fun printName() {
            subPrint()
        }
        private fun subPrint() { // 这里并非继承Person
            println("subPrint")
        }
    }
    person.printName() // person是一个对象,直接调用

 

标签:伴生,对象,kotlin,Companion,Person,User,nickname
From: https://www.cnblogs.com/czwlinux/p/17780609.html

相关文章

  • Java基础 获取 class 对象的三种方式
    ①Class.forName("全类名")  →  最为常用全类名:包名+类名Class的首字母是大写的,所以是一个类名,是用来描述字节码文件的。这个类里面有一个静态方法叫 forName,参数可以传递一个类的全类名,可以获取到参数的字节码文件对象 ②类名.class  →  这种方式更......
  • Math 对象
    MathMath是js为我们提供的计算对象(单例内置对象)1Math对象的属性属性说明Math.E自然对象e的基数eMath.LN1010为底的自然对数Math.LN22为底的自然对数Math.LOG2E以2为底e的对数Math.LOG10E以10为底e的对数Math.PI圆周率πMath.SQRT1_21/2......
  • 重学面向对象,体会设计模式
    先上图(学长今晚讲得好激情,就像哈佛大学cs50的老师~~~~)图一让你明白,在Java帝国,你有多么渺小 回忆一下学长讲课的思路~Driver这个类里面封装了很多各种各样的方法,包括接学生回家,包括开车的时速,里面包括了,司机本身的一个职责,以及车的一个功能,但问一个问题,如果今天司机的大巴......
  • python面向对象-学习笔记(六、方法相关的补充)
    私有化方法私有方法classPerson:__age=18#私有方法def__run(self):print("run")#def_Person__run(self):#print("Personrun")p=Person()#p.__run()#p._Person__run()print(Person.__dict__)内置特殊方法......
  • Unity显示一个对象的像素个数
    下图显示了该面片占用的像素个数为147456。因为面片的大小为1,坐标为(0,0.5f,0)。相机为正交视角,OrthoSize为1.面片完全显示且高度为(768/2)^2=384^2=147456。另外,可以推测,pixelshader渲染会在所有对象的vertexshader计算结束后开始。即使面片被遮挡,但如果没做处理依然......
  • Optional.ofNullable()方法, 参数list或者map如果为null执行 ofNullable(创建个新对象
    Optional.ofNullable()方法举个栗子publicstaticvoidmain(String[]args){List<String>list=null;list.forEach(x->System.out.println(x));}工作中经常会遇到,查询返回空,如果没有判空处理,一不小心就会空指针异常。加上if判断处理也可以,但是jdk1.......
  • python面向对象-学习笔记(三、类方法、实例方法、静态方法)
    方法相关方法的概念描述一个目标的行为动作和函数相似封装了一系列行为动作。比如一个人怎么吃,怎么喝,怎么玩...都可以被调用最主要区别:调用方式方法的划分实例方法:默认第一个参数是一个实例类方法:默认第一个参数是类静态方法:没有默认参数注意划分的依据:方法的第一......
  • python面向对象-学习笔记(四、类相关的补充)
    元类创建类对象的类对象怎么产生的?由类创建出来的。类是不是对象?是所以类对象是不是由另外一个类创建出来的?是,元类创建类对象的另外一种方式#创建类对象的另外一种方式defrun(self):print("run",self)dog=type("Dog",(),{"count":1,"run":run})prin......
  • python面向对象-学习笔记(五、属性相关的补充)
    私有化属性注意python并没有真正支持私有化,但是可以使用下划线完成伪私有的效果类属性(方法)和实例属性(方法)遵循相同的规则公有属性a在类的内部可以访问在子类的内部可以访问在模块其他地方类的属性可以访问子类的属性可以访问类的实例的属性可以访问子类的......
  • python面向对象-学习笔记(二、类&对象的属性)
    如何定义一个类?创建类的格式class类名: pass怎么通过类,创建出一个对象?创建类,并实例化对象classMoney:passone=Money()#打印类print(Money)#打印类的实例print(one)类的别名和打印类的名称classMoney:pass#打印类的名称print(Money.__na......