美文网首页
Android学习Kotlin之四、定义类-初始化-继承

Android学习Kotlin之四、定义类-初始化-继承

作者: 艾曼大山 | 来源:发表于2022-01-03 10:28 被阅读0次

    Kotlin标准库函数

    定义一个类很简单,和java一样声明需要的变量属性,在kotlin中省略了get()和set()函数默认支持get()和set(),并且可以自定义get()和set()函数;初始化类时顺序很重要,如果代码顺序写错了会很容易报错;类通过open修饰可被继承,和java不同的是kotlin的函数也需要通过open修饰后子类才可以继承。

    Kotlin

    其它Kotlin文章
    Android学习Kotlin之一、常量-条件-函数-高阶函数
    Android学习Kotlin之二、Null安全 -字符串操作- 类型转换
    Android学习Kotlin之三、标准库函数-集合List-Set-Map
    Android学习Kotlin之四、定义类-初始化-继承
    Android学习Kotlin之五、对象-接口-抽象类
    Android学习Kotlin之六、泛型-扩展函数

    本编文章会讲到的知识点

    • 定义类
      • field
      • 计算属性
    • 初始化类
      • 主构造函数使用临时变量
      • 主构造函数中直接定义属性变量
      • 次构造函数
      • 初始化块
      • 初始化顺序
      • 延迟初始化lateinit
      • 惰性初始化lazy
    • 继承
      • open继承
      • 类型检测
      • as智能转换
      • Any类

    定义类

    field

    针对你定义的每一个属性,Kotlin都会产生-个field、一个getter、 以及一个setter, field用来存储属性数据,你不能直接定义field, Kotlin会封装 field,保护它里面的数据,只暴露给getter和setter使用。属性的getter方法决定你如何读取属性值,每个属性都有getter方法,setter方 法决定你如何给属性赋值,所以只有可变属性才会有setter方法,尽管Kotlin会自动提供默认的getter和setter方法,但在需要控制如何读写属性数据时,你也可以自定义他们。

    • 定义一个Student类,里面定义变量,kotlin默认提供的就有get、set方法,也可以自定义get、set方法。
    class Student {
        var name = "小明"
            get() = field.capitalize()
            set(value) {
                field = value.trim()//自定义set去除空格
            }
        var age = -12
            //自定义get和set函数,实际根据自己需求来自定义get和set
            get() = field.absoluteValue//自定义取绝对值
            set(value) {
                field = value.absoluteValue
            }
    
        var adder:String? = "杭州"
    }
    
    • 创建Student对象,调用属性的get、set方法使用
     var student = Student()
        student.name = " 老王  "//估计前后写空格
        println(student.name)//打印老王 没有空格
    
        println(student.age)
        student.age = -6
        println(student.age)//打印 是正6 因为自定义get中取绝对值了
    
        fun getAdder(){
            //如果adder不为空才会打印
            student?.adder?.also {
                println("地址=${it}")
            }
        }
        getAdder()
    
    计算属性

    计算属性是通过- -个覆盖的get或set运算符来定义,这时field就不需要 了。

        var value: Int? = null
            get() = (1..10).random()//自定义返回值get不使用field
    
        var student = Student()
        println(student.value)//返回1-10的随机数
    

    初始化类

    主构造函数使用临时变量

    我们在Teacher类的定义头中定义一个主构造函数,使用临时变量为Teacher的各个属性提供初始值,在Kotlin中, 为便于识别,临时变量(包括仅引用一-次的参数),通常都会以下划线开头的名字命名。

     class Teacher(
        _name: String,
        _age: Int,
    ) {
        var name = _name
        var age = _age
        override fun toString(): String {
            return "Teacher(name='$name', age=$age)"
        }
    }
    
        var teacher = Teacher("何炅", 50)
        println(teacher.name)//何炅
        println(teacher.toString())//Teacher(name='何炅', age=50)
    
    打印.png
    主构造函数中直接定义属性变量

    Kotlin允许你不使用临时变量赋值,而是直接用一个定义同时指定参数和类属性,通常,我们更喜欢用这种方式定义类属性,因为他会减少重复代码。定义构造函数时,可以给构造函数参数指定默认值,如果用户调用时不提供值参,就使用这个默认值。

    class Teacher2(
        var name: String,
        var age: Int = 10//可以设置默认值
    ) {
        override fun toString(): String {
            return "Teacher2(name='$name', age=$age)"
        }
    }
    
        var teacher2 = Teacher2("黄磊", 52)
        println(teacher2.name)//黄磊
        println(teacher2.toString())//Teacher2(name='黄磊', age=52)
    
    次构造函数

    有主就有次,对应主构造函数的是次构造函数,我们可以定义多个次构造函数来配置不同的参数组合,通过this指向把值传递给了主构造函数。可以在次构造函数中进行初始化代码逻辑,比如修改参数值。

    class Teacher3(
        var name: String,
        var age: Int,
    ) {
        //次构造函数 通过this指向把值传递给了主构造函数
        constructor(name:String):this(name,0){
            //这里可以进行初始化代码逻辑,给age赋值
            this.age = 18
        }
        override fun toString(): String {
            return "Teacher3(name='$name', age=$age)"
        }
    }
    
        val teacher3 = Teacher3("黄晓明")//调用的是次构造函数 没有传age值
        println(teacher3.toString())//Teacher3(name='黄晓明', age=18)
    
    初始化块

    初始化块可以设置变量或值,以及执行有效性检查, 如检查传给某构造函数的值是否有效,初始化块代码会在构造类实例时执行。

    class Teacher4(
        var name: String,
        var age: Int,
    ) {
        init {
            println("${name} "+if (age>18) "满18" else "未满18")
            age = if (age > 18) 1 else 0 //判断age的值 然后修改age的值
        }
        override fun toString(): String {
            return "Teacher4(name='$name', age=$age)"
        }
    }
    
        var teacher4 = Teacher4("马云",20)
        println(teacher4.toString())//Teacher4(name='马云', age=1)
    
    初始化顺序

    1.主构造函数里声明的属性
    2.类级别的属性赋值
    3.init初始化块里的属性赋值和函数调用
    4.次构造函数里的属性赋值和函数调用

    class Teacher5(
        var name: String,
        var age: Int,
    ) {
        var hight: Int = 175
    
        init {
            println("初始化块 ${name} " + if (age > 18) "满18" else "未满18")
        }
    
        constructor(name: String) : this(name, 10) {
            hight = 180
            println("这里是次构造函数")
        }
    
        override fun toString(): String {
            return "Teacher5(name='$name', age=$age, hight=$hight)"
        }
    }
    
        var teacher5 = Teacher5("小马云")
        println(teacher5.toString())
    
    初始化顺序
    延迟初始化lateinit
    • 只能用在var变量上;
    • 使用lateinit关键字相当于做了一一个约定:在用它之前负责初始化;
    • 只要无法确认lateinit变量是否完成初始化,可以执行isInitialized检查;

    只能用在var变量上;该修饰只能用于类体中(不是在主构造函数中)声明的var属性,注意是var(可变属性)并且仅当该属性没有自定义getter或setter时,该属性必须是非空类型,并且不能是原生类型。

    class Teacher6 {
        lateinit var name: String
    
        init {
            name = "中国惊奇先生"
        }
    
        fun getName() {
            if (::name.isInitialized) println(name) else println("name为空")
        }
    }
    
        val teacher6 = Teacher6()
        teacher6.getName()
    
    惰性初始化lazy
    • 只能用在val变量上

    延迟初始化并不是推后初始化的唯一方式, 你也可以暂时不初始化某个变量,直到首次使用它,这个叫作惰性初始化。

    class Teacher7 {
        val name: String by lazy {
            println("马上赋值")
            "镇魂街"
        }
    
        fun getName(){
            println(name)
        }
    }
       val teacher7 = Teacher7()
        //第一次调用打印 “马上赋值” “镇魂街”
        teacher7.getName()
        //第二次调用只打印值,不会执行lazy{}过程
        teacher7.getName()
    

    继承

    open继承

    默认都是封闭的,要让某个类开放继承,必须使用open关键字修饰它。父类的函数也要以open关键字修饰,子类才能覆盖它。

    open class Animal(var name: String) {
        //父类的函数也要以open关键字修饰,子类才能覆盖它。
        open fun getName() {
            println("this is ${name} ")
        }
    }
    
    class Cat : Animal("小狗") {
        override fun getName() {
    //        super.getName()
            println("this2 is ${name} ")
        }
    }
    
        val cat = Cat()
        println(cat.name)//小狗
        cat.getName()//this2 is 小狗 
    
    类型检测

    Kotlin的is运算符是个不错的工具,可以用来检查某个对象的类型。

        val cat2 = Cat()
        println(cat2 is Cat)//true
        println(cat2 is Animal)//true
    
    as智能转换

    as操作符声明,这是一个类型转换。/为了避免抛出异常,可以使用安全转换操作符 as?,它可以在失败时返回 null。

        println(cat2 as Animal)
        var c = cat as Animal
    //    var c1 = cat2 as Animal2//报错 java.lang.ClassCastException
        var c1 = cat2 as? Animal2//为了避免抛出异常,可以使用安全转换操作符 as?,它可以在失败时返回 null
        println(c1)
        c?.getName()//this2 is 小狗
    
    Any类

    无须在代码里显示指定,每一-个类都会继承一个共同的叫作Any的超类。

        val cat = Cat()
        println(cat is Any)// true
        println(cat as Any)// com.example.kotlinjetpack.kotlin.Cat@66d3c617
    

    相关文章

      网友评论

          本文标题:Android学习Kotlin之四、定义类-初始化-继承

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