美文网首页kotlin
Kotlin面向对象 (8)✔️强大的object关键字

Kotlin面向对象 (8)✔️强大的object关键字

作者: 狼性代码人 | 来源:发表于2019-05-30 23:28 被阅读13次
    • 对象表达式
    • 对象声明 (单例,隶属于——饿汉模式)
    • 伴生对象

    object 关键字主要在声明一个类的同时创建这个类的对象。具体而言它有三方面应用:对象表达式、对象声明 和 伴生对象。

    一、对象表达式

    • object 关键字可以声明对象表达式,对象表达式用来替代 Java 中的匿名内部类。
    class View {
        fun handler(listener: OnClickListener?) {
            listener?.onClick()
        }
    }
    
    interface OnClickListener {
        fun onClick()
    }
    
    fun main(args: Array<String>) {
        var i = 0;
        val view = View()
        view.handler(object :OnClickListener {
            override fun onClick() {
                println("对象表达式作为函数参数... i=$i")
                i++
            }
        })
    }
    

      上述代码中 view.handler 函数的参数是对象表达式,object 说明表达式是对象表达式,该表达式声明了一个实现 OnClickListener 接口的匿名类,同时创建对象。

    • 对象表达式的匿名类可以实现接口,也可以继承具体类或抽象类。
    open class Person(val name: String, var age: Int) // 1️⃣
    
    fun main(args: Array<String>) {
        val person = object :Person("小三", 18), OnClickListener { // 2️⃣
    
            override fun onClick() {
                println("实现接口 onClick 函数...")
            }
    
            override fun toString(): String {
                return "[name: $name, age: $age]"
            }
        }
    
        person.onClick()
    
        println(person)
    }
    
    2019-05-30 18:41:17.171 31741-31741/cn.ak.kot I/System.out: 实现接口 onClick 函数...
    2019-05-30 18:41:17.171 31741-31741/cn.ak.kot I/System.out: [name: 小三, age: 18]
    

      上面代码第1️⃣行是声明一个Person的具体类,代码第2️⃣行是声明对象表达式,该表达式声明实现了 OnClickListener 接口,且继承 Person 类的匿名类,之间用逗号 (,) 分隔。Person("小三", 18) 是调用 Person 的构造函数。

    • 没有具体的父类也可以使用对象表达式。
    fun main(args: Array<String>) {
        val rect = object {
            val x: Int = 10
            val y: Int
            
            init {
                y = 10
            }
            
            fun area() = x * y
    
            override fun toString(): String {
                return "[x:$x, y:$y]"
            }
        }
        
        println(rect.area())    // 100
        println(rect)           // [x:10, y:10]
    }
    

    二、对象声明 (单例)

      单例设计模式可以保证在整个的系统运行过程中只有一个实例,单例模式在开发中是经常使用的设计模式,所以kotlin把单例设计模式上升到语法层面。

    • 单例对象声明,object 关键字后面是类名,在对象声明的同时可以指定对象实现接口或父类,在类体中可以有自己的成员函数和属性,在调用时,可以通过类名直接访问单例对象的函数和属性。
    open class EnglishTool(var name: String) {
    
        override fun toString(): String {
            return "[name: $name]"
        }
    }
    
    interface Upper {
        fun toUpper(word: String): String
    }
    
    object Toolkit: EnglishTool("英语"), Upper {
    
        override fun toUpper(word: String): String {
            return word.toUpperCase()
        }
    
        fun printUpperWord(word: String) {
            println(toUpper(word))
        }
    }
    
    fun main(args: Array<String>) {
        Toolkit.printUpperWord("hello ak")
        println(Toolkit)
    
        Toolkit.name = "中文"
        println(Toolkit)
    }
    
    2019-05-30 19:12:01.819 3724-3724/cn.ak.kot I/System.out: HELLO AK
    2019-05-30 19:12:01.819 3724-3724/cn.ak.kot I/System.out: [name: 英语]
    2019-05-30 19:12:01.819 3724-3724/cn.ak.kot I/System.out: [name: 中文]
    
    • 为什么是饿汉模式?
    // kotlin 单例代码
    object Toolkit {
    }
    
    // kotlin 转换后的 java 代码
    package cn.ak.kotmodule;
    
    import kotlin.Metadata;
    
    @Metadata(
       mv = {1, 1, 15},
       bv = {1, 0, 3},
       k = 1,
       d1 = {"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\bÆ\u0002\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002¨\u0006\u0003"},
       d2 = {"Lcn/ak/kotmodule/Toolkit;", "", "()V", "kotlin_module"}
    )
    public final class Toolkit {
       public static final Toolkit INSTANCE;
    
       private Toolkit() {
       }
    
       static {
          Toolkit var0 = new Toolkit();
          INSTANCE = var0;
       }
    }
    

      从 kotlin 解释出的 java 很直白的可以出是一个 饿汉模式。至于怎么查看 kotlin 解释出的 java 代码,请自行百度,本文中是开发工具是 Android Studio

    • object 对象声明不能嵌套在其他 函数 中, 但可以嵌套在其他 或 其他 object对象声明 中。
    object Toolkit {
    
        fun doSomethings(): Int {
            // object Singleton { // 编译不过
            //     val x = 10
            // }
            return 0
        }
    
        object Singleton {
            val x = 10
        }
    }
    
    class Outer {
        object Singleton {
            val x = 10
        }
    }
    
    fun main(args: Array<String>) {
        println(Toolkit.Singleton.x)    // 10
        println(Outer.Singleton.x)      // 10
    }
    

    三、伴生对象

      在很多语言中静态成员的声明使用 static 关键字修饰,而 kotlin 没有 static 关键字,也没有静态成员,它是通过声明伴生对象实现 Java 静态成员的访问方式。

    1、声明伴生对象
    class Account {
        var amout = 0.0
        var owner: String? =  null
    
        fun messageWith(amt: Double): String {
            val interest = Account.interestBy(amt)
            return "${owner}的利息是$interest"
        }
    
         companion object {
             // 静态属性
             var interestRate: Double = 0.0
             
             //静态方法
             fun interestBy(amt:Double): Double {
                 // 静态函数可以访问静态属性和其它静态函数
                 return interestRate * amt
             }
             
             init { // 1️⃣
                 println("静态代码块被调用")
                 // 初始化静态属性
                 interestRate = 0.0668
             }
         }
    }
    
    fun main(args: Array<String>) {
        val account = Account() // 2️⃣
        // 访问伴生对象属性
        println(Account.interestRate)
        // 访问伴生对象函数
        println(Account.interestBy(1000.0))
    }
    
    • 伴生对象,使用关键字 companionobject 声明。作为对象可以有成员属性和函数,在容器类外访问伴生对象的属性和函数,可以通过容器类名直接访问。代码第1️⃣行是伴生对象的 init 初始化代码块,它相当于 Java 中的静态代码,它可以初始化静态属性,该代码块会在容器类第一次访问时调用,代码第2️⃣行是第一次访问 Account 类,此时会调用伴生对象的 init 初始化代码块。

      注意:伴生对象函数可以访问自己的属性和函数,但不能访问容器类中的成员属性和函数。容器类可以访问伴生对象的函数和属性。这一点与 Java 类中的静态成员和静态方法是一样的,只能访问本类的静态成员和其它的静态函数。

    2、伴生对象非省略形式

    上面示例中,事实上省略了伴生对象的名字,声明伴生对象时还可以添加继承父类或实现接口。

    open class Text(var name: String) {
        override fun toString(): String {
            return "[name: $name]"
        }
    }
    
    class GView {
    
        companion object GButton : Text("按钮"), OnClickListener {
    
            override fun onClick() {
                println("点击了伴生对象的onClick...")
            }
    
            init {
                println("伴生对象初始化代码块")
                name = "View的伴生对象Button的成员属性name=按钮"
            }
        }
    }
    
    fun main(args: Array<String>) {
    //    val v = GView()
        println(GView.name)
        println(GView.GButton.name)
    
        GView.onClick()
        GView.GButton.onClick()
    }
    
    2019-05-30 23:44:45.237 12893-12893/com.ktln.cltor I/System.out: 伴生对象初始化代码块
    2019-05-30 23:44:45.237 12893-12893/com.ktln.cltor I/System.out: View的伴生对象Button的成员属性name=按钮
    2019-05-30 23:44:45.237 12893-12893/com.ktln.cltor I/System.out: View的伴生对象Button的成员属性name=按钮
    2019-05-30 23:44:45.237 12893-12893/com.ktln.cltor I/System.out: 点击了伴生对象的onClick...
    2019-05-30 23:44:45.238 12893-12893/com.ktln.cltor I/System.out: 点击了伴生对象的onClick...
    

      讲解:上面代码中 GButton 是伴生对象名,Text("按钮") 是继承 Text 类,OnClickLisener 是实现该接口。一旦显示指定伴生对象名后,在调用时可以加上伴生对象名,当然省略伴生对象名也可以调用它的属性和函数。

    3、伴生对象扩展

    伴生对象中可以添加扩展函数和属性。

    val GView.GButton.length: Int
        get() = this.name.length
    
    fun GView.GButton.display() {
        println("[name: $name, length: $length]")
    }
    
    fun main(args: Array<String>) {
        // 访问伴生对象扩展属性
        println(GView.GButton.length)
        println(GView.length)
        // 访问伴生对象扩展函数
        GView.GButton.display()
        GView.display()
    }
    
    2019-05-31 00:26:43.813 17030-17030/com.ktln.cltor I/System.out: 伴生对象初始化代码块
    2019-05-31 00:26:43.814 17030-17030/com.ktln.cltor I/System.out: 27
    2019-05-31 00:26:43.814 17030-17030/com.ktln.cltor I/System.out: 27
    2019-05-31 00:26:43.814 17030-17030/com.ktln.cltor I/System.out: [name: View的伴生对象Button的成员属性name=按钮, length: 27]
    2019-05-31 00:26:43.814 17030-17030/com.ktln.cltor I/System.out: [name: View的伴生对象Button的成员属性name=按钮, length: 27]
    

      从上述代码可见,调用伴生对象的扩展函数与普通函数访问没有区别。

    相关文章

      网友评论

        本文标题:Kotlin面向对象 (8)✔️强大的object关键字

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