小鹏学习kotlin 类与继承

转载自:https://blog.csdn.net/stanny_bing/article/details/73549480?utm_source=gold_browser_extension


本篇博客主要讲解kotlin中关于类和接口的相关知识

类这个东西使用和java比较类似,最简单的如下


    class innerClass {
        
    }
再class之前可以加private protected internal 或者public,默认不写就是public了


另外需要注意的是,如果类的内部没有实体,可以直接这么写


class innerClass

不加括号

构造方法

提到类,肯定还会提到他的构造方法

kotlin中的构造方法和java有很大的不同,kotlin的构造方法分为两种:主构造方法、次构造方法

1.主构造方法:

    class InnerClass constructor(name: String) {
 
    }
是的,kotlin中的主构造方法,直接就属于类名的一部分,是直接放在类名之后的

构造函数就是构造方法的意思,如果主构造方法中没有注解或者可见性修饰符的时候,构造函数可以省略不写

    class InnerClass(name: String){
 
    }
同时,每个类都提供了一个初始化方法,用于在构造之后,进行初始化

如下:


    class InnerClass constructor(name: String) {
 
        var name: String? = null
 
        init {
            this.name = name
        }
 
    }

另外除了在init中使用,也可以在类本身中使用

    class InnerClass constructor(name: String) { 
        var myName = name
 
    }

除了在类体中初始化参数,还可以在构造方法的参数前加var或者val直接进行赋值

    class InnerClass(var name: String) {

  class InnerClass(var name:String){ 
 
        init { 
            println(name)
        } 
 
    }

此时就相当于已经走了初始化、赋值两个步骤


2.次构造方法

次构造方法和java类似,是放在类里面的

    class InnerClass{
 
        constructor(name: String, age: Int){
 
        }
 
    }

此时是当不存在主构造方法时的写法

如果类存在主构造方法,就必须在次构造方法后调用this方法,将方法委托给主构造方法,即如果从次构造方法中进来后,还需要再次进入主构造方法


    class InnerClass(name: String) {
 
        constructor(name: String, age: Int) : this(name) {
 
        }
 
    }

次级构造方法可以有很多个,主构造方法只能存在一个


    class InnerClass(name: String) {
 
        constructor(name: String, age: Int) : this(name) {
 
        }
 
        constructor(name: String, age: Int, sex: String) : this(name, age) {
 
        }
 
    }

并且次级构造方法的this,不仅仅可以委托给主构造方法,像上面这样,也可以委托给其他的次级构造方法,只要保证最终会委托到主构造方法即可,像下面这样是不行的

    class InnerClass(name: String) {
 
        constructor(name: String, age: Int) : this(name, age, "") {
 
        }
 
        constructor(name: String, age: Int, sex: String) : this(name, age) {
 
        }
 
    }
两个次构造方法相互委托,会出现错误提示:There is a cycle in the delegation calls chain----委托调用链中有一个循环。

再来,我们可以看到在上面的代码中出现了三个name这参数,那么在初始化init的时候,我们调用name是指的哪一个呢?

很明显,指的是主构造方法

    class InnerClass(name: String) {
 
        constructor(name: String, age: Int) : this(name) {
 
        }
 
        constructor(name: String, age: Int, sex: String) : this(name, age) {
 
        }
 
        init {
            println(name)//这个name指的是主构造方法中的name
        }
 
    }

那么如果主构造方法没有(后面会讲到并不是没有,其实是空),我们再使用name呢


    class InnerClass{
 
        constructor(name: String, age: Int) {
 
        }
 
        constructor(name: String, age: Int, sex: String) : this(name, age) {
 
        }
 
        init {
            println(name)//这个是会报错的,找不到name
        }
 
    }

找不到name,即只有主构造方法中的参数是全局的


3.构造方法的可见性

如果像下面这样:

    class InnerClass {
 
    }

其实,他是相当于

    class InnerClass constructor(){
 
    }

也相当于

    class InnerClass public constructor(){
 
    }

默认是public的,这样我们在初始化的时候,可以这样

var inner = InnerClass()
那么,如果我们不想让我的类被其他类构造呢,比如我只能当父类,不允许其他类跳过子类直接构造呢?

那么就可以这样写

    class InnerClass private constructor(){
 
    }

这样,我们就不可以在其他地方构造这个类了

这一点,需要特别记住的

类的构造

刚刚,我们提到了,var inner = InnerClass()

这样的语句,这就是类的构建了,等同于java的

InnerClass inner = new InnerClass(); 

注意, Kotlin中是没有new的

其他的话,其实和java就没有多大区别呢,如果构造需要参数,直接传入就可以了

var inner = InnerClass(“name”)

类的继承

在kotlin中,类的继承和java差别还是挺大的

kotlin的继承使用的是“:”冒号,在kotlin里面,冒号的使用是非常频繁的,继承需要、定义需要、操作需要。

如下:

    open class Person{
 
    }
 
    class Man : Person(){
        
    }
这就是最简单的继承了,注意看里面的person这个类前面有一个open关键词,open在kotlin中代表了,这个类可以被继承,如果不写,其他类是无法继承该类的,这样的目的就是为了方便筛选出可继承类与不可继承类,因为在java中,如果一个类打出extends之后,会出现很多很多的类,有些类名字相似,你甚至不知道该继承哪一个,特别是在api的使用上。

然后就是复杂一点的用法:

    open class Person(name: String, sex: String) {
 
    }
 
    class Man(name: String) : Person(name, "man") {
 
    }
在继承的时候,如果父类有构造方法,子类必须完整的传入构造需要的参数去进行初始化

如果一个父类存在构造方法,并且子类并没有在主构造方法中进行构造,那么就需要在次构造方法中使用super关键字,委托给父类的构造方法

    open class Person {
 
        constructor(name: String) {
 
        }
 
    }
 
    class Man : Person {
 
        constructor(name: String) : super(name) {
 
        }
 
    }

同时,假如父类有多个构造方法,子类可以任意委托给其中一个

 

   open class Person {
 
        constructor(name: String) {
 
        }
        
        constructor(name: String, age : Int){
            
        }
 
    }
 
    class Man : Person {
 
        constructor(name: String) : super(name,0) {
 
        }
 
    }

方法的重写

子类重写父类的方法,和上面一样,也是需要在方法前加open关键字,默认修饰关键字为final

    open class Person {
 
        open fun fatherFoo(){
 
        }
 
    }
 
    class Man : Person() {
 
        override fun fatherFoo() {
            super.fatherFoo()
        }
 
    }

如上,fatherFoo这个方法,如果想被子类重写,就需要在前面加上open关键字,同时,子类如果要重写父类的方法,就需要在方法前加上override这个关键字,不过这个关键字倒是不需要我们自己去写,在重写时,系统会自动添加上的。

至于里面的super,我就不说了,和java一样

再一个,如果此时有一个类,继承自Man这个类,那么此时fatherFoo这个方法默认就是可以被重写的,就不需要再添加open关键字,默认就是open

    open class Person {
 
        open fun fatherFoo(){
 
        }
 
    }
 
    open class Man : Person() {
 
        override fun fatherFoo() {
            super.fatherFoo()
        }
 
    }
 
    class Child : Man(){
        override fun fatherFoo() {
            super.fatherFoo()
        }
    }

那么,如果我们只想Man重写来自Person的方法,不允许Man的子类重写他父类的父类的方法,就需要在Man类的方法前加final关键字

        final override fun fatherFoo() {
            super.fatherFoo()
        }
此时,Child就不允许重写该方法了,该操作也极大的利于我们限制最外层类触及里层类的方法。

抽象类

类的抽象,如下

    abstract class Person {
        abstract fun faFoo(): String
        open fun getName() {
            println(faFoo())
        }
    }
和java差不多,抽象类和抽象方法前加abstract即可

另外,子类可以使用抽象方法重写父类的一般方法

    open class Person {
        open fun getName() {
            
        }
    }
 
    abstract class Man : Person() {
        abstract override fun getName()
    }
当然也不能瞎重写,父类的方法都没返回,你抽象方法也是没有返回的


最后提醒一点,抽象类,抽象方法,本来就拿给子类用的,所以,abstract修饰的方法、类,默认自带open

    abstract class Person {//这里不需要open关键字,子类也可以继承
         abstract fun getName()//这里也不需要open关键字,子类仍然可以重写
    }
 
    abstract class Man : Person() {
        abstract override fun getName()
    }



猜你喜欢

转载自blog.csdn.net/jiankeufo/article/details/80885066