美文网首页
【KtAndroid - 7】继承、抽象类、接口

【KtAndroid - 7】继承、抽象类、接口

作者: 会飞的小魚 | 来源:发表于2020-04-29 20:20 被阅读0次

书接上篇……

之所以将这三个写在一起而不与类写在一起,大概是因为这三者惺惺相惜吧。(类写完了才发现,如果一个开一篇文章的话……有划水的赶脚!嘿嘿)

在面向对象中这继承、抽象类、接口三者可是占着不弱的低位哈,可以说有了它们,面向对象才具备了灵魂。

在上篇文章我说了类的定义,对象的创建,其实都没什么,但是!!构造方法的定义与使用一定要摸清楚。因为,在用惯了java后对于接下来的继承、抽象类、接口难免会觉得

1. 继承

一. 基本继承

首先来说说继承!

来一段代码:

package cn.xinidi.java;

/**
 * @author Gang
 * @Date 2020/4/29
 * @Version 1.0
 */
public class JavaFile {
    public static void main(String[] args) {
        Man man = new Man();
        System.out.println(man.head);
    }
}


class Person{
    String head = "头";
}

class Man extends Person{
    public Man() {
        this.head = "男人的头";
    }
}
1.png

这是java中的继承。

来看kotlin中的继承:

package cn.xinidi.kotlin

/**
 * @author Gang
 * @Date 2020/4/29
 * @Version 1.0
 */
class KtFile {
    companion object{
        @JvmStatic
        fun main(args: Array<String>) {
            println("kt:${Man().head}")
        }
    }
}

open class Person {
    var head = "头"
}

class Man : Person() {
    init {
        head = "男人的头"
    }
}
2.png

好了,这就是基本的继承了。

要点:java没什么可说的。然鹅,对于kotlin来说,父类 Person 使用了一个open关键字,以达到子类可以继承它。(你也可以试试去掉open)

子类继承的关键字并不是extends而是一个:,其实这个:在kotlin中还有其他用法,不要急,马上会说。

接下来说方法的继承,子类重写父类方法:

open class Person {
    var head = "头"
    open fun jump() {
        println("跳!")
    }
}

class Man : Person() {
    init {
        head = "男人的头"
    }

    override fun jump(){
        println("男人在跳!")
    }
}

父类方法jump也是用了open来声明,该方法可以被继承重新,但是在子类中我们在jump前加了一个override。说起override,我相信在java中没少见它吧。

在java中随你自己的心情写或者是不写它,编译器不会提醒你的代码有问题。

但是在kotlin中,你必须写它,不写就报错,不给糖就捣蛋。

同样的,重写父类字段也是通过override

open class Person {
    open var head = "头"
    open fun jump() {
        println("跳!")
    }
}

class Man : Person() {
    override var head = "男人的头"
    /*init {
        head = "男人的头"
    }*/

    override fun jump() {
        println("男人在跳!")
    }
}

二. 父类的构造函数

如果继承的父类带有参数构造函数,那么该怎么继承呢?

open class Animal(var type: String) {
    ……
}

class Dog(name: String, type: String) : Animal(type) {
    ……
}

这是在子类拥有主构造函数的情况下,如果没有主构造函数,那么次构造函数怎么写呢?

open class Animal(var type: String) {
    ……
}

class Cat : Animal {
    constructor(name: String, type: String) : super(type) {
        ……
    }

    constructor(name: String, age: Int, type: String) : super(type) {
        ……
    }
}

子类中可使用super调用父类的方法。

与java一样,kotlin只支持单继承

3.png

这里又一点要注意:

子类继承父类时,不能有跟父类同名的变量,除非父类中该变量为 private,或者在父类中该变量为 open 并且子类是用 override 关键字重写的。

2. 抽象类

类的继承说完了,那么接下来就是今天的第二个猪脚。

与java一样,抽象类的声明也是使用abstract

abstract class AbsKtPerson {
    open abstract fun run()
    open abstract fun jump()
}

继承实现:

4.png

3. 接口

kotlin中的接口也是用interface来定义

interface InterfacePerson{
    open fun eat()
    open fun speak(){
        println("说话!")
    }
}

interface InterfaceTool{
    open fun knife()
}

class Impl : AbsKtPerson(),InterfacePerson,InterfaceTool{
    override fun run() {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun jump() {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun eat() {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun knife() {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }
}

同时在kotlin中,接口中支持写方法体,实现了方法体的方法,子类可以选择性实现。

override fun speak() {
    super.speak()
}

如果多个上级中存在了相同的已实现的方法,如:

abstract class AbsKtPerson {
    open abstract fun run()
    open abstract fun jump()
    //在抽象类中实现了
    open fun speak(){
        println("AbsKtPerson说话!")
    }
}

interface InterfacePerson{
    open fun eat()
    //在接口中实现了
    open fun speak(){
        println("InterfacePerson说话!")
    }
}

将会出现以下错误

5.png

你可以通过泛型指定使用其中一个的super(但是,该super除了某些特定情况下必须由子类调用父类,其他情况下并不是必须的)。

也就是你可以这样:

6.png

但是遇到必要调用的时候:

7.png

这里我要来说一个容易混淆的地方

也就是上文提到的:

在子类中 无论是实现接口,还是继承父类都是使用的:

那么区别在于

8.png

对,就是这个()。如果是继承类,只需要在后面加一个括号(别傻啊,这括号是干嘛的?继承哪块已经说了,负责将父类需要的参数传过去,如果父类有一个参数构造函数,那就不能直接打括号了)

另外还有一种写法,可以稍微记一下

9.png

好了就到这,这些东西我只讲了个大概,并不是我讲了,你看了,就完了。

要自己多写多练,另外kotlin中的多态与java中是一样的!

4. 关于“::”引用的说明

在java中我们可以通过接口实现方法回调,特别是在android这一块使用得较多。

在kotlin有一种写法,就是将方法作为参数传给需要被调函数。

……是不是听起来有点绕?没关系,看代码就是了

12.png

上图中首先创建了一个名为t的KtTest对象,然后通过t::func传给了show方法

show方法中的参数是一个名为funcM的参数名,类型为()->Unit

()->Unit表示一个返回空的方法。

如果不好理解,可以这么看

13.png

运行结果:

14.png

*注意:如果对象没有创建(new),那么不能直接传方法,至于为什么?对象都没有创建,虚拟机怎么知道该调用谁的方法。

5. 总结

  1. kotlin中,继承需要父类使用open关键字,子类实现则需要以override关键字,不能省略
  2. kotlin中,抽象类与java中几乎一样。
  3. kotlin中,接口与抽像类一样可以有方法实现,子类继承可以选择性覆写已经实现的方法
  4. kotlin中,如果子类的上级存在两个已经实现的相同方法可以通过super<泛型>.方法名指定使用上级的方法,但不是必须要写。
  5. kotlin中,继承与接口的实现都是用的:表达式,区分的方式就是(),也就是子类继承父类相当于创建了一个父类对象,然而接口则不需要。
  6. kotlin中,支持函数(方法)作为参数传递,使用::表达式

相关文章

网友评论

      本文标题:【KtAndroid - 7】继承、抽象类、接口

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