美文网首页
kotlin基础学习-5(对象,继承相关)

kotlin基础学习-5(对象,继承相关)

作者: ftd黑马 | 来源:发表于2022-04-15 09:57 被阅读0次
    • 继承与重载的关键字open
      类默认都是封闭的,要想某个类开放继承,必须使用open关键字修饰它
    在main函数中调用
        //继承
        val carProduct : Product = CarProduct()
        println(carProduct.description())
        println(carProduct.load())
    
    //继承
    open class Product(val name : String){
        fun description () = "Product === $name"
    
        open fun load () = "Loading..."
    }
    
    //继承父类,父类必须用open关键字,否则默认类是final
    class CarProduct:Product("aodi"){
        //这里的override是关键字,重写某父类方法需要加override,并且父类方法必须声明为open
        override fun load () ="aodi Loading..."
    
        fun carMethod() = "car special Method"
    }
    
    • 类型转换
      is as 关键字
      kotlin中的Any超类,类似于java中的object
    //类型转换
        println(carProduct is Product)
        println(carProduct is CarProduct)
        if(carProduct is CarProduct){
            println((carProduct as CarProduct).carMethod())
        }
    
    • 对象声明
      使用object关键字,可以定义一个只能产生一个实例的类--单例
      使用object关键字有三种方式
      1.对象声明
    //在kotlin中,声明一个类为单例很方便,直接使用object
    object ApplicationConfig{
        init {
            println("applicationConfig init...")
        }
    
        fun doSomething(){
            println("doSomething")
        }
    }
    
    在main函数中调用
        //在kotlin中,声明一个类为单例很方便,直接使用object
        ApplicationConfig.doSomething()//这里并不是说是静态的,而是声明了是单例类,这里就可以直接使用类名作为对象名
    
        //指向的都是同一个对象,因为它是单例
        println(ApplicationConfig)
        println(ApplicationConfig)
        println(ApplicationConfig)
    
    

    2.对象表达式

    open class Player8 {
        open fun load() = "loading nothing"
    }
    在main函数中调用
        //对象表达式作为子类
        //类似于java中的new 一个OnclickListener,这个匿名类依然遵循object关键字的原则,一旦实例化,只能有唯一一个实例存在
        val p  = object : Player8(){
            override fun load() = "匿名类的loading方法"
        }
        println(p.load())
    

    3.伴生对象

    //伴生对象
    open class SinggleTest{
        //只有初始化SinggleTest类或者调用load函数时,伴生对象的内容才会载入
        //而且无论实例化多少次,这个伴生对象始终只有一个实例存在。有点类似java的static
        //一个类里只能有一个伴生对象
        companion object{
            private const val PATH = "xxxxxxx"
            fun load() = println("伴生对象的方法执行")
        }
    }
    在main函数中调用
        //伴生对象
        SinggleTest.load()
    
    • 嵌套类
    //嵌套类(内部类)
    //如果一个类只对另一个类有用,那么将其嵌入到该类中并使两个类保持在一起就很合逻辑,可以使用嵌套类
    class Player1{
        class Equipment(var name:String){
            fun show() = println("equipment:$name")
        }
        fun battle() = println("ak47...")
    }
    在main函数中调用
        //嵌套类(内部类)
        Player1.Equipment("天空套").show()
    
    • 数据类
      专门用来存储数据的类
      看源码可以看到,默认实现了toString方法,打印的时属性值
      ==符合默认情况下,在any超类里面比较的是它们的引用值,数据类提供了equals和hashcode的个性化实现,比较的是内容
    /**
     * 使用数据类的条件
     *  对于那些经常需要比较,复制或打印自身内容的类,数据类很适用。然而,一个类要成为数据类,也要符合一定条件,总结下来,主要有三个方面
     *  1.数据类必须有至少带一个参数的主构造函数
     *  2.数据类主构造函数的参数必须是var 或者 val
     *  3.数据类不能使用abstract,open,sealed和inner修饰符
     */
    //数据类,用data关键字修饰
    data class Coordinate(val x : Int,val y : Int){
    }
    
    在main函数中调用
        //这里打印的是Coordinate(x=1, y=2)。如果不用data修饰,打印的是Coordinate@60e53b93
        println(Coordinate(1,2))
    
        //这里结果是true,如果类名不用data修饰,则是false
        println(Coordinate(1,2) == Coordinate(1,2))
    
    • copy函数
    //data数据类的copy函数demo
    data class StudentOrigin(
        val name: String,
        var age : Int,
        var isNormal : Boolean
    ){
        var score = 0
    
        //次构造函数,有主就有次,我们可以定义多个次构造函数来配置不同的参数组合
        constructor(_name: String) : this (_name,age = 10,isNormal = false){
            //copy函数不会调用这,copy出去的值还是0
            score = 10
        }
    
    
        //初始化块,与java的static不一样,这里的初始化块是构造函数执行的时候,就会执行初始化快
        init {
            //先决函数,如果boolean值是false,执行lambda抛出异常
            require(age > 0) {
                "age must be positive"
            }
            require(name.isNotBlank()){
                "student must have a name"
            }
        }
    
        override fun toString(): String {
            return "StudentOrigin(name='$name', age=$age, isNormal=$isNormal, score=$score)"
        }
    }
    在main函数中调用
        //copy函数,它可以将数据类的其他属性都copy过来。但是这里有一个坑,次构造函数里面修改过的值不能copy,需要重新赋值
        val s = StudentOrigin("Jack")
        val copy = s.copy("Rose")
        println(s)
        println(copy)
    
    • 解构声明
    //解构语法的demo类
    class Demo(val x:Int , val y : Int){
        //这里的component1等名字都是固定写法,不能修改
        operator fun component1() = x
        operator fun component2() = y
    }
    //数据类,用data关键字修饰
    data class Coordinate(val x : Int,val y : Int){
    }
    
    在main函数中调用
        //数据类默认支持解构语法,如果不是数据类,则需要我们手动在类里面重写方法,就如果解构语法demo类一样。
        val (x,y) = Coordinate(1,2)
        println("$x,$y")
    
        //解构语法的demo类
        val (a,b) = Demo(3,4)
        println("$a,$b")
    
    • 运算符重载
      使用operator关键字
    /**
     * 运算符重载,常见的操作符
     *
     *
     *  操作符                 函数名                 作用
     *  +                     plus                  把一个对象添加到另一个对象里
     *  +=                    plusAssign            把一个对象添加到另一个对象里,然后将结果赋值给第一个对象
     *  ==                    equals                如果两个对象相等,则返回true,否则返回false
     *  >                     compareTo             如果左边的对象大于右边的对象,就返回true,否则返回false
     *  []                    get                   返回集合中指定位置的元素
     *  ..                    rangeTo               创建一个range对象
     *  in                    contains              如果对象包含在集合里,则返回true
     *
     */
    
    
    data class Coordinate2(val x: Int,val y: Int){
        //运算符重载,使用operator关键字
        operator fun plus(other:Coordinate2) = Coordinate2(x+other.x,y+other.y)
    }
    在main函数中调用
        //运算符重载
        val coordinate2 = Coordinate2(10,50)
        val coordinate3 = Coordinate2(20,100)
        //如果下面的运算符不重写,这里使用+号就会报错
        println(coordinate2+coordinate3)
    
    • 枚举类
      枚举类也可以定义函数
    data class Coordinate2(val x: Int,val y: Int){
        //运算符重载,使用operator关键字
        operator fun plus(other:Coordinate2) = Coordinate2(x+other.x,y+other.y)
    }
    
    //枚举类,也可以定义函数
    enum class Direction(val coordinate:Coordinate2){
        EAST(Coordinate2(1,2)),
        WEST(Coordinate2(3,4)),
        NORTH(Coordinate2(5,6)),
        SOUTH(Coordinate2(7,8));
    
        fun updateCoordinate(other: Coordinate2) = Coordinate2(
            other.x + coordinate.x,
            other.y + coordinate.y
        )
    }
    在main函数中调用
        //枚举类,用来定义常量集合的一种特殊类
        println(Direction.EAST) //输出的就是枚举的字符串值
        println(Direction.WEST.updateCoordinate(Coordinate2(10,20)))
    
    • 密封类
      密封类(sealed),从枚举类思考更复杂的需求,比如我需要控制其中一个对象具有某种属性,这时候使用密封类,但不要混淆,密封类不是枚举
      密封类可以用来定义一个类似于枚举类的类型,但是可以更灵活的控制某个子类型
      密封类可以有若干个子类,要继承密封类,这些子类必须和它定义在同一个文件中
    //密封类demo
    class Driver(var status: LicenseStatus){
        fun checkLicense () : String {
            return when(status){
                is LicenseStatus.Unqualified -> "没资格"
                is LicenseStatus.Learning -> "正在学"
                is LicenseStatus.Qualified -> "有资格,驾驶证编号: " + (this.status as LicenseStatus.Qualified).licenseId
            }
        }
    
    }
    
    //密封类
    sealed class LicenseStatus{
        object Unqualified : LicenseStatus()                             //这里没有属性,所以把它定义为单例
        object Learning : LicenseStatus()                                //这里没有属性,所以把它定义为单例
        class Qualified (var licenseId:String) : LicenseStatus()         //这里有一个id的属性,所以不定义为单例
    }
    在main函数中调用
        println(Driver(LicenseStatus.Qualified("2820202")).checkLicense())
        println(Driver(LicenseStatus.Learning).checkLicense())
    

    相关文章

      网友评论

          本文标题:kotlin基础学习-5(对象,继承相关)

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