美文网首页
kotlin 对象

kotlin 对象

作者: jxiang112 | 来源:发表于2022-05-17 14:06 被阅读0次

    kotlin对象是很灵活的,常见的方式类似java一样new 一个类的实例对象,也可以通过匿名对象的方式创建对象,匿名对象的方式可以指定其父类或父接口,且可以同时一个父类或多个接口,这样可以达到——有时可能需要对某个类或者接口稍作临时小改动而不想通过创建子类继承的方式。

    1、实例对象

    实例对象是最简单也是最常用的方式,对现有的类创建一个实例对象:

    class A {
    }
    val objA = A()
    

    这种方式创建的对象可以对类的可访问成员进行访问,无任何限制

    2、匿名对象

    2.1、对象表达式

    对象表达式的语法为:

    object [[superClass()][,][superInterface][,superInterface]......] { 
    [override list] 
    }
    

    对象表达式如果没有指定要继承的父类/父接口的情况下,其类型为Any类型,如果指定了父类则需要指定构造函数并传递所需的参数,在对象表达式实体{}中可以重写父类/父接口的成员。
    对象表达式可以用作赋值语句、函数的参数、函数返回类型等
    对象表达式作为赋值语句赋值给某个变量时,如果继承了一个类和多个接口,则需要显示指定成员变量的类型classType:

    val tempObj: TObj2 = object : TObj2(21), TObj4 {
        override fun tFun() {
            println("x = ${super.x} and do do ")
        }
    
    }
    

    tempObj继承了TObj2、TObj4 ,需要显示指定其类型是TObj2或者TObj4
    用对象表达时需要注意使用的场景:

    • 作为公有函数的返回值或者公有属性类型时,如果没有继承父类,则公有函数的返回值或者公有属性的类型是Any,此时是无法反问匿名对象内部的可访问成员;如果继承有父类则是父类类型,可以访问父类型的可访问成员,但不能访问匿名对象内部的定义的可访问成员
    • 作为私有成员类型时,则是匿名对象类型,此时可以反问匿名对象内部的可访问成员

    例子如下:

    open class TObj3 {
        val y = 30
    }
    
    class TObj {
        //私有变量,没有继承任何类,变量类型为匿名对象类型
        private val pObj = object  {
            val x = 1
        }
        
        //公有变量,没有继承任何类,变量类型为Any
        val pubObj = object {
            val x = 2
        }
        
        //公有函数,继承了TObj3,函数返回类型为TObj3
        fun pubFun() = object: TObj3(){
            val x = 3
        }
    
        fun main() {
            //私有变量类型为匿名对象,所以可以访问匿名对象的x
            println("private x = ${pObj.x}")
            //公有变量类型为Any,所以无法访问匿名对象的x
            println("public x = ${pubObj}")
            //公有函数,匿名对象继承了TObj3,所以函数返回的对象可以反问TObj3的y,但是不能反问匿名对象的x
            println("public fun = ${pubFun().y}")
        }
    }
    

    2.2、对象声明

    语法:

    object objectName [:superClass[,][superInterface]...] {
      [override list]
      [self params/funs]
    }
    

    对象声明的限制:

    • 不能用作赋值语句
    • 不能用在局部作用域(如函数、内部类等),但可以嵌套在在非内部类、其他对象声明中

    用法:对象声明的方式是线程安全,其属于单例声明,使用时直接使用对象名称.成员即可,如:

    open class A1 {
        val x = 10
    }
    interface I1 {
        fun fun1()
    }
    object StaticObj : A1(), I1{
        override fun fun1() {
            println("x = ${super.x}")
        }
    }
    
    class ObjClient {
        fun main() {
            StaticObj.x
            StaticObj.fun1()
        }
    }
    
    2.2.1、伴生对象

    在类内部的对象声明加上companion标记,表示此对象为伴生对象,语法为:

    companion object [objName] [:[superClass][,][superInterface]....] {
      [override list]
      [params/funs]
    }
    

    在对象声明的前面加companion标记表示此对象为伴生对象。
    伴生对象与对象声明有啥区别呢?

    • 伴生对象可以省略对象名称,省略对象名称时默认名称是Companion;而对象声明则不能省略
    • 调用伴生对象内部成员时可以省略对象名称;而对象声明则不能省略,如:
    class A {
        companion object ObjA {
            val x = 123
        }
    }
    
    val value = A.x  // 等价于:A.ObjA.x
    

    调用伴生对象的成员时,看起来跟java中的静态成员一样,但伴生对象的成员本质上不是静态成员,除非用@JvmStatic注解进行修饰,伴生对象的成员才会变成真正的静态成员,如:

    class A {
        companion object ObjA {
            @JvmStatic
            val x = 123
        }
    }
    

    2.3、对象表达和对象声明的差异

    • 对象表达式在使用时立即执行或者初始化
    • 对象声明在第一次访问到时延迟初始化
    • 伴生对象在其所在的类被加载解析时,才进行初始化,与java的静态语义是一样的

    相关文章

      网友评论

          本文标题:kotlin 对象

          本文链接:https://www.haomeiwen.com/subject/dbogurtx.html