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

2022-01-03  本文已影响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

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

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? = "杭州"
}
 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变量上;该修饰只能用于类体中(不是在主构造函数中)声明的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

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

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
上一篇下一篇

猜你喜欢

热点阅读