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

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容