Kotlin学习3—面向对象编程

1. 继承与构造函数
1.1 继承 :

在Kotlin中,任何一个非抽象类默认都是不可以被继承,相当于JAVA中给类声明了final关键字

抽象类本身无法创建实例,一定要由子类去继承它才能创建实例,因此抽象类必须可以被继承才行

之所以这么设计,应该是与var关键字差不多,最好都是不可变的,因为一个类允许被继承的话,无法预知子类会存在什么风险

在Effective JAVA一书中提到,如果一个类不是专门为继承而设计,就一个为这个类加上final声明

若要使一个类可以被继承,只需在该类前加上open关键字即可,子类继承父类由JAVA中的extends关键字转变为 :

    // 父类Person
    open class Person {
        var age: Int? = 0

        var name: String? = ""

        fun say() {
            println("age = $age, name = $name")
        }
    }

    // 子类Student
    class Student : Person() {

    }
    

为什么子类继承父类后,Person类的后面需要加上一个括号?因为在Kotlin中,还会涉及到主构造函数、次构造函数等方面

1.2 主构造函数

在每个类中默认都会有一个不带参数的主构造函数,主构造函数的特点是没有函数体,直接定义在类名后面即可

在Kotlin中,我们可以将相关的字段放在主构造函数中,例如:

    // 将新增的两个字段 height 与 school 放在主构造函数中
    class Student(val height: Int, val school: String) : Person() {
        // 主构造函数没有函数体,若要编写其中的逻辑,则可以在init结构体中编写
        init {

        }
    }

为什么子类继承父类时,需要带上括号呢?因为继承特性,子类继承父类时,子类的构造函数必须调用父类的构造函数,在Kotlin里,子类的主构造函数调用父类的哪个构造函数,在继承时通过括号来指定

    // 父类Person
    open class Person(var age: Int, var name: String) {
        constructor()  : this(0, "") {
            // 无参构造函数
        }
    
        fun say() {
            println("age = $age, name = $name")
        }
    }

    // 将子类Student
    class Student(val height: Int, val school: String, age: Int, name: String) : Person(age, name) {

    }

子类指定调用父类的带参构造函数后,子类主构造函数中的age、name字段,不能再将它们声明为val或者var,因为在主构造函数中会自动成为该类的字段,就会导致与父类中同名的age、name冲突,因此在该参数前不加任何关键字,让它作用域仅限定在主构造函数中即可

1.3 次构造函数

每个类中只能有一个主构造函数,但是可以有多个次构造函数

注意:Kotlin规定,当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(包括间接调用)

    class Student(val height: Int, val school: String, age: Int, name: String) 
        : Person(age, name) {

        constructor(age: Int, name: String) : this(0, "", age, name) {

        }

        constructor() : this(0, "") {

        }
    }

次构造函数是通过constructor关键字来定义的,以上面的例子为例:
第一个次构造函数接收age和name两个参数,然后又通过this调用其主构造函数,并将height与school设定默认值;
第二个次构造函数不接受任何参数,通过this关键字调用之前定义的第一个次构造函数,并将age和name设定默认值,因此相当于间接调用了主构造函数

有一种特殊的场景,当类中仅有次构造函数,没有主构造函数的时候,此时继承父类时,不需要加上括号

    class Child : Person {
        constructor(age: Int, name: String) : super(age, name) {

        }
    }

由于没有主构造函数,次构造函数只能直接调用父类的构造函数,只需将this转换成super关键字,跟JAVA很相似

2. 接口 interface

Kotlin中的接口部分与Java中的几乎一致,接口用于实现多态编程的重要组成部分

    interface Study {
        fun read()

        fun write()
    }

    // Student类实现Study接口
    class Student : Study {
        override fun read() {

        }

        override fun write() {

        }
    }
    

在Kotlin中,为了让接口更加灵活,还增加了一个额外的功能:允许对接口中定义的函数进行默认实现。这个功能在Java 1.8之后也支持

    interface Study {
        fun read()

        fun write()

        // 函数默认实现,不需强制被实现
        fun sleep() {

        }
    }

    // Student类实现Study接口
    class Student : Study {
        override fun read() {

        }

        override fun write() {

        }

    }
3. Kotlin关键字

private:作用与Java中的一致,只对当前类内部可见

public:与Java一致,对所有类可见,在Kotlin中public是默认项,而在Java中default是默认项

protected:在Kotlin中仅对当前类与子类可见

internal:在Kotlin中,抛弃了default关键字,引入新的可见性概念internal,只对同一模块中的类可见,常用于模块化编程中

4. 数据类 data class

在Java中,定义一个数据类,通常需要重写equals()、hashCode()、toString()这几个方法。

而在Kotlin中,新增了一个关键字data,当在一个类前面声明了data关键字时,就表明你定义这个类为数据类,Kotlin会根据主构造函数中的参数将equals()、hashCode()、toString()等方法自动生成

    data class Student2(val name: String, val age: Int)
5. 单例类 object class

在项目,最常用到的设计模式便是单例模式,通常在Java中定义个单例类的时候,需要编写很多行代码才能实现,而在Kotlin中,为我们提供了单例类

在Kotlin中创建一个单例类极其简单,仅需在定义类的时候,将class关键字改写成object关键字即可

    // 单例类
    object Student3 {
        fun eat() {

        }
    }
    
    class Main {
        // 调用单例类Student3中的eat()方法
        fun main() {
            Student3.eat()
        }
    }
    

调用单例类中方法的方式,就比较类似于调用Java中的静态方法

6. 密封类 sealed class

在使用密封类前,我们用when语句来做判断时,我们不得不再编写一个else条件否则,Kotlin编译器会认为这里缺少条件分支,无法编译通过。但当我们编写了else条件,下次新增一个新的条件时,忘记在when语句中添加这个条件,这时执行when语句的时候,就会跑到else条件中去,这并不是我们想要的结果

因此,在Kotlin中,为我们新增了密封类sealed class,很好地解决了这个问题。当我们在when语句中传入一个密封类变量作为条件时,Kotlin编译器会自动检查该密封类有哪些子类,并强制要求对这些子类进行条件处理

注意:密封类及其所有子类只能定义在同一个文件的顶层位置,不能嵌套在其他类中,这是被密封类底层的实现机制所限制的

    // SealedClass.kt 顶层文件中定义
    sealed class Result
    class Success(): Result()
    class Failure(): Result()
    
    
    // 普通class文件中函数实现
    fun getResult(result: Result) = when(result) {
        is Success -> {
            println("Success")
        }

        is Failure -> {
            println("Failure")
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值