美文网首页
Kotlin——面向对象(4)

Kotlin——面向对象(4)

作者: 被时光移动的城 | 来源:发表于2018-09-05 17:46 被阅读14次

    1、面向对象-抽象类与接口

    1)什么是接口
    接口,直观理解就是一种约定
    kotlin的接口与Objcet-C的Protocal比较类似
    举例:

    interface InputDevice{
    fun input(event:Any)
    }
    

    2}接口
    a.接口不能有状态
    b.必须由类对其进行实现后使用
    3)抽象类
    a.实现了一部分协议的半成品
    b.可以有状态,可以有方法实现
    c.必须由子类继承后使用
    4)抽象类和接口的共性
    a.比较抽象,不能直接实例化
    b.有需要子类(实现类)实现的方法
    c.父类(接口)变量可以接受子类(实现类)的实例赋值
    d.抽象类反映本质,接口体现能力
    5)抽象类和接口的区别
    a.抽象类有状态,接口没有状态
    b.抽象类有方法实现,接口只能有无状态的默认实现
    c.抽象类只能单继承,接口可以多实现

    2、继承

    1)父类需要open才可以被继承
    2)父类方法、属性需要open才可以被复写
    3)接口、接口方法、抽象类默认为open
    4)复写父类(实现接口)的方法需要override关键字
    5)class D:A(),B,C
    6)继承类时实际上是调用了父类构造方法
    7)类只能单继承,接口可以多实现
    接口代理

    class Leader(val dr:Drive,val pp:PPT):D by dr,P by pp

    接口方法实现交给代理类实现
    事例:

    interface  D{
        fun drive()
    }
    
    interface P{
        fun write()
    }
     class Drive:D{
       override fun drive(){
            println("开车")
        }
    }
    
    class PPT:P{
      override fun write(){
            println("写ppt...")
        }
    }
    
    //接口代理
    class Leader(val dr:Drive,val pp:PPT):D by dr,P by pp
    
    fun main(args: Array<String>) {
        val lead = Leader(pp=PPT(),dr=Drive())
        //接口代理调用
        lead.drive()
        lead.write()
    }
    

    接口方法冲突
    1)接口方法可以有默认实现
    2)方法名、方法参数以及返回值相同,否则会有冲突
    3)子类(实现类)必须复写冲突方法
    4)super<[父类(接口)名]>.[方法名]([参数列表])
    事例:

    open class A {
        open fun x(): Int = 'A'.toInt()
    }
    
    interface B {
        fun x(): Int = 'B'.toInt()
    }
    
    interface C {
        fun x(): Int = 'C'.toInt()
    }
    
    class F(var y: Int) : B, C, A() {
        override fun x(): Int {
            return when {
                y > 0 -> super<A>.x()
                y < 0 -> super<B>.x()
                else -> super<C>.x()
            }
        }
    }
    
    fun main(args: Array<String>) {
        println(F(-1).x())//B
        println(F(0).x())//C
        println(F(1).x())//A
    }
    

    运行结果:66,67,65

    3、类及其成员的可见性(private,protected,internal,public)

    注:internal在和java兼容方面依旧存在问题,暂不建议使用


    可见性对比.png

    4、object

    1)只有一个实例的类
    2)不能自定义构造方法
    3)可以实现接口、继承父类
    4)本质上就是单例模式最基本的实现
    注:如果不考虑懒加载等因素,Kotlin中写单例,使用的是object。

    5、伴生对象与静态成员

    1)每个类可以对应一个伴生对象
    2)伴生对象的成员全局独一份
    3)伴生对象的成员类似Java中的静态成员
    4)静态成员考虑用包级函数、变量替代
    5)JvmField和JvmStatic的使用
    事例:
    无论加不加@JvmStatic@JvmField在kotlin都可正常调用,而Java若想调用,则必须添加这两个注解。

    class Latitude private constructor(val d:Double){
        companion object {
            @JvmStatic
            fun la(d: Double):Latitude{
                return Latitude(d)
            }
            @JvmStatic
            fun getD(latitude: Latitude):Latitude{
                return Latitude(latitude.d);
            }
            @JvmField
            val TAG = "TAG"
        }
    }
    

    kotlin中调用

    fun main(args: Array<String>) {
    var latitude = Latitude.la(6.66)
    val latitude2 = Latitude.getD(latitude)
    val tag = Latitude.TAG
    }
    

    java中调用

    Latitude latitude = Latitude.la(3.234);
    Latitude latitude2 = Latitude.getD(latitude);
    String tag = Latitude.TAG;
    

    6、方法重载与默认参数

    1)方法重载
    a.Overloads
    b.名称相同、参数不同的方法
    c.Jvm函数签名的概念:函数名、参数列表
    d.跟返回值无关
    2)默认参数
    a.为函数参数设定一个默认值
    b.可以为任意位置的参数设置默认值
    c.函数调用产生混淆时用具名参数
    3)方法重载和默认参数
    a.二者的相关性以及@JvmOverloads(给java中调用kotin中的默认参数时使用)
    事例:

    class Overloads {
    //    fun a(): Int {
    //        return 0
    //    }
       //  @JvmOverloads
        fun a(int: Int = 0): Int {
            return int
        }
    
        fun a(str: String): Int {
            return str.toInt()
        }
    }
    
    fun main(args: Array<String>) {
        val ovarLoads = Overloads()
        ovarLoads.a(1)
        ovarLoads.a("2")
    //kotlin中调用
        println(ovarLoads.a())
    }
    
    未加@JvmOverLoads时javad调用.png
    加上@JvmOverLoads时java的调用.png

    b.避免定义关系不大的重载
    c.不好的设计

    List.remove(Int)
    List.remove(Object)

    事例:


    java中remove.png
    kotlin中remove.png

    7、扩展成员

    为现有类添加方法属性

    fun X.y():Z{...}
    val X.m 注:扩展属性不能初始化,类似接口属性
    Java调用扩展成员类似调用静态方法
    事例:

    二元运算符.png
    fun main(args: Array<String>) {
        println("abc".times(6))
        println("a" * 6)
        println("a".a )
        println("b".b)
    }
    
    operator fun String.times(num: Int): String {
        val sb = StringBuffer()
        if (num > 0) {
            for (i in 0 until num) {
                sb.append(this)
            }
        }
        return sb.toString()
    }
    
    val String.a
        get() = 5
    var String.b
        set(value){}
        get() = 6
    

    运行结果:


    运行结果.png

    8、属性代理

    1)定义方法

    val/var <property name>:<Type> by <expression>

    2)代理者需要实现相应的setValue/getValue方法
    事例:

    class Delegate {
        val x1 by lazy {
            "Hello X"
        }
        var x2 by X()
        var x3 by X()
    
    }
    
    class X {
        private var value: String? = null
    
        operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
            println("getValue---------$thisRef--------------------${property.name}")
            return value ?: ""
        }
    
        operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
            println("setValue------------$thisRef----------------${property.name}-----------$value")
            this.value = value
        }
    }
    
    fun main(args: Array<String>) {
        val delegate = Delegate()
        println(delegate.x1)
        println(delegate.x2)
        println(delegate.x3)
        delegate.x3 = "666666666666666666666"
        println(delegate.x3)
    }
    

    输出结果:


    运行结果截图.png

    9、数据类(allOpen,noArg插件,再见,javaBean)

    1)data class默认实现了copy、toString、hashCode、equals等方法
    2)componentN方法
    3)allOpen和noArg插件

    10、内部类(this@Outter,this@Inner)

    内部类
    a.定义在类内部的类
    b.与类成员有相似的访问控制
    c.默认是静态内部类,非静态用inner关键字
    d.this@Outter,this@Inner的用法
    匿名内部类
    a.没有定义名字的内部类
    b.类名编译时生成,类似Outter$1.class这样的类名
    c.可继承父类、实现多个接口,与Java注意区别

    11、枚举(enum)

    实例可数的类,注意枚举也是类
    可以修改构造,添加成员
    可以提升代码的表现力,也有一定的性能开销

    12、密封类(sealed Class)

    1)子类可数
    kotlin版本<1.1,子类必须定义为封闭类的内部类
    v1.1,子类只需要与密封类在同一文件中
    2)与枚举类似却又不同

    相关文章

      网友评论

          本文标题:Kotlin——面向对象(4)

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