美文网首页
kotlin语言学习10 ——kotlin 可见性与扩展

kotlin语言学习10 ——kotlin 可见性与扩展

作者: LiangLliu | 来源:发表于2019-12-26 11:12 被阅读0次

    本节主要介绍kotlin的可见性与kotlin中的扩展功能的使用,包括:扩展类、扩展方法、扩展伴生对象、扩展属性等。

    1、kotlin可见性

    关键字:
    public: 在不低kotlin进行修饰时,默认为 public。
    protected : 不能用在顶层函数或者类上面,用在修饰属性上面,子类和同一个类可以使用。
    internal : 只能在同一个模块下使用,即:整个工程(一个模块)。
    private : 私有的,只能在该文件上可用。

    可见性的用法和Java类似:

    open class Class {
    
        private val b = 3
    
        protected open val c = 4
    
        internal val d = 5
    
    }
    

    2、kotlin 扩展

    如果要对一个类进行扩展,在Java中,我们可以使用 interface,装饰模式来达到目的,但是在kotlin专门提供了扩展的功能。

    2.1、扩展类 :

    class ExtensionTest {
        fun add(a: Int, b: Int): Int = a + b
        fun subtract(a: Int, b: Int): Int = a - b
    }
    

    现在有个需求要对上面的类添加,乘法和除法功能,在kotlin我们可以直接对该类的方法进行扩展:

    /**
     * 扩展类:
     */
    class ExtensionTest {
        fun add(a: Int, b: Int): Int = a + b
        fun subtract(a: Int, b: Int): Int = a - b
    }
    
    /**
     * 扩展上面类的功能,扩展机制
     */
    fun ExtensionTest.multiply(a: Int, b: Int): Int = a * b
    
    fun main() {
        val extensionTest  = ExtensionTest()
        println(extensionTest.add(4,5))
        println(extensionTest.subtract(4,5))
        println(extensionTest.multiply(4,5))
    }
    

    以上代码的运行结果如下:

    以上代码的运行结果
    我们可以看到该类中确实多了乘法的功能。

    注意 :

    • 1、扩展函数的解析是静态的,该类添加了一方法,并没有插入到原来的类中,本质上没有对原有的类插入任何属性(可以使用javap工具 反编译看结果)
    • 2、扩展函数的解析是静态分发的,而不是动态的,即扩展不支持多态,调用只取决于对象的谁能ing类型
    •  多态:通过父类型的引用去指向一个对象,当在调用该对象时,到底是父类,还是子类,取决于真正运行期对象的方法     
      
    • 3、调用是由对象的声明类型决定的,而不是由对象的实际类型决定
    open class AA
    
    class BB : AA()
    
    // 扩展 AA
    fun AA.a() = "a"
    
    // 扩展 BB
    fun BB.a() = "b"
    
    fun myPrint(aa: AA) {
        println(aa.a())
    }
    fun main() {
        myPrint(AA())   // a
        myPrint(BB())   // a
    }
    

    我们可以发现上面的结果都是 定义方法中传入参数的类型。

    2.2、扩展方法

    • 扩展类的方法和扩展类的方法完全一样
    • 在扩展方法时原来函数的优先级比较高
    /**
     * 扩展类的方法和扩展类的方法完全一样
     * 在扩展方法时原来函数的优先级比较高
     */
    class CC {
        fun foo() {
            println("CCC")
        }
    }
    
    fun CC.foo() {
        println("CC.foo")
    }
    
    // 扩展方法时支持方法重载
    fun CC.foo(i: Int) {
        println("CC.Int $i")
    
    }
    
    fun main() {
        CC().foo()  // CCC
        CC().foo(5)  // CC.Int 5
    }
    

    注意: 重载可以对空类型进行扩展, 提供可空类型后就不用再次做检查。

    /**
     * 重载可以对可空类型进行扩展
     * 提供可空类型后就不用再次做检查
     */
    fun Any?.toString(): String {
        if (null == this) {
            return "null"
        }
        return toString()
    }
    

    2.3、扩展属性

    /**
     * 扩展属性
     */
    class MyExtensionProperty {
    
    }
    
    val MyExtensionProperty.name : String
        get() = "hello"
    
    fun main() {
        val myExtensionProperty = MyExtensionProperty()
        println(myExtensionProperty.name) // hello
    }
    

    扩展属性后的结果如下图:

    执行结果

    2.4、扩展伴生对象

    /**
     * 扩展伴生对象
     *
     */
    class ExtensionCompanionObj {
        // 伴生对象
        companion object MyObject {
        }
    }
    
    fun ExtensionCompanionObj.MyObject.method() {
        println("hello world")
    }
    
    fun main() {
        ExtensionCompanionObj.method()  // hello world
    }
    

    代码结果如下图 :

    代码执行结果

    2.5、扩展作用域

    先给出结论:

    • 1、扩展函数所定义在的类实例叫 分发接受者
    • 2、扩展函数所扩展的类的示例叫 扩展接受者
    • 3、当以上名字出现冲突时,扩展接受者的优先级比较高

    示例如下:

    /**
     * 扩展作用域
     *
     * 1、扩展函数所定义在的类实例叫 分发接受者
     * 2、扩展函数所扩展的类的示例叫 扩展接受者
     * 3、当以上名字出现冲突时,扩展接受者的优先级比较高
     */
    class ExtendedScope {
        fun method() {
            println("ExtendedScope")
        }
    }
    
    /**
     * 扩展上面的类
     */
    class ExtendedScope2 {
        fun method2() {
            println("")
        }
    
        // 在类中扩展另一个类
        fun ExtendedScope.hello() {
            // 可以使用扩展类中的内容,也可以调用这个类的方法
            method()
            method2()
        }
    
        fun world(extendedScope: ExtendedScope) {
            extendedScope.method()
        }
    
        // 扩展的作用域,只能在该类中使用
        fun ExtendedScope.output() {
            println(toString())
            println(this@ExtendedScope2.toString())
        }
    
        fun test() {
            var extendedScope = ExtendedScope()
            extendedScope.output()
        }
    }
    
    fun main() {
        // 通过扩展可以解决Java中充斥的各种辅助类问题
        val extendedScope2 = ExtendedScope2()
        extendedScope2.test()
        // 运行结果
        // com.liang.kotlin.basic.advanced.spread.ExtendedScope@3cd1a2f1
        // com.liang.kotlin.basic.advanced.spread.ExtendedScope2@2f0e140b
    }
    

    注意:
    ExtendedScope并不能调用ExtendedScope2中对它扩展的方法,受到作用域限制

    作用域限制
    上面的图,我们可以看到,ExtendedScope2中对ExtendedScope扩展的output方法,并不能被ExtendScope调用。

    相关文章

      网友评论

          本文标题:kotlin语言学习10 ——kotlin 可见性与扩展

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