十、Kotlin学习之定义类的继承结构

本文深入探讨了Kotlin语言的特性,包括与Java的不同之处,如默认final和public的声明,内部类与嵌套类的区别,以及open、final、abstract修饰符的使用。同时,文章详细介绍了可见性修饰符、密封类的概念,以及它们如何影响类和接口的实现。

与JAVA不同,Kotlin的声明默认是final和public的。此外,嵌套的类默认并不是内部类:他们并没有包含对其外部的隐式引用

一、Kotlin中的接口

interface Animal {
    fun eat() {}
}

class Dog : Animal {
    override fun eat() {}//重写eat函数
}

kotlin中,使用冒号代替java中的extends和implements关键字。和java一样,一个类可以实现任意多个接口,但是只能继承一个类。

与java中的@Override注解类似,override修饰符用来标注被重写的父类或者接口的方法和函数。与java不同的是override修饰符是强制要求的。

接口的函数可以有一个默认的实现。

interface Animal {
    fun eat() {//默认实现,如果子类不重写eat函数,会执行默认现实,如果重写就执行子类重写的函数
        println("default method")
    }
}

class Dog : Animal {
}

fun main() {
    Dog().eat()//打印“default method”
}

二、open、final、abstract修饰符

Java的类和方法默认是open的,但是Kotlin中默认都是final的。
如果你想创建一个类的子类,需要使用open修饰符来标识这个类。此外,需要给内一个可以被重写的属性和方法添加open修饰符。

open class Animal {
    open fun eat() {}
}

class Dog : Animal() {
    override fun eat(){}
}

如果重写了一个类和接口的成员,重写了的成员默认是open的。如果你想改变这一行为,组织你的类的子类重写你的实现,可以显式将重写的成员标注为final。

open class Animal {
    final fun eat() {}//子类无法继承eat函数,因为被final修饰
}

class Dog : Animal() {}

在Kotlin中,同Java一样,可以将一个类声明为abstract,抽象类不可以被实例化,抽象成员始终是open的,所以不需要显示地使用open修饰符。

abstract class Animal {//可以被继承
    abstract fun eat()//可以被重写
    fun move(){}//默认final,不可以重写
}

class Dog : Animal() {
    override fun eat() {}
}

在接口中,不能使用final、open、abstract,接口成员始终都是open的,不能将其声明为fianl,如果他没有函数体他就是abstract,但是这个关键字并不是必须的。

修饰符相关成员评注
final不能被重写类中成员默认使用
open可以被重写需要明确地表明
abstract必须被重写只能在抽象类中使用,抽象成员不能有实现
override重写父类或者接口中的成员如果没有使用final表明,重写的成员默认是开放的

三、可见性修饰符

Kotlin和java类似,同样可以使用public、protected和private修饰符。但是默认可见性是不同的,Kotlin默认是public,如果省略修饰符,声明就是public的。Java模式可见性是包可见,在Kotlin中没有使用。

Kotlin提供了一种新的修饰符“internal”,表示“只在模块内部可见”,一个模块就是一组一起编译的Kotlin文件。

Kotlin允许在顶层声明中使用private可见性,包括类、函数和属性。这些都是文件可见。这就是另一种隐藏子系统实现细节的非常有用的方式。

修饰符类成员顶层声明
public(默认)所有地方可见所有地方可见
internal模块中可见模块中可见
protected子类中可见-
private类中可见文件中可见
internal open class Animal {//模块可见,可以被继承
    private fun eat(){}//类内可见
    protected fun move(){}//子类可见
}

fun Animal.sleep(){//错误,默认是public,所有地方可见性,不能给低可见性类internal扩展
    eat()//错误,类中可见,不可调用
    move()//错误,子类才可调用
}

kotlin禁止从public函数sleep去引用低可见性类型Animal(internal类型)。类的扩展函数不能访问他的private和protected修饰的成员。

四、内部类和嵌套类

内部类默认是嵌套类。像Java一样,Kotlin中可以在另一个类中声明一个类,区别是Kotlin的嵌套不能访问外部类的实例,除非特别要求。

class Animal {
    fun eat(){}
    
    class Cat {
        fun move(){
            eat()//编译错误,调用不到外部类的函数
        }
    }
}

Kotlin中没有显示修饰符的嵌套类与Java中的static嵌套类一样。要把它变成一个内部类来持有一个外部类引用的话需要使用修饰符inner。

class Animal {
    fun eat(){}

    inner class Cat {//inner修饰类持有外部类引用
        fun move(){
            eat()//编译成功,Cat类持有外部类引用
        }
    }
}

五、密封类

when语句作为函数返回值时必须提供else分支处理其他分支。

interface Animal

class Cat : Animal

class Dog : Animal

fun test(color: Animal) =
    when (color) {
        is Cat -> "cat"
        is Dog -> "dog"
        else -> "else"//必须有else分支

    }

当使用when结构来执行表达式时候,Kotlin编译器会强制检查默认选项。总是添加else分支比较麻烦,并且你添加一个新子类,编译器并不会发现改变。如果忘记添加新分支,会走else分支,可能会有bug。这个问题Kotlin提供了解决方案:sealed类

为父类添加sealed修饰符,对可能创建的子类进行严格的限制。所有的子类都必须嵌套在父类中。所以在when表达式中不需要再写else分支。

sealed class Animal {//密封类,所有的子类都必须嵌套在父类内

    class Cat : Animal()

    class Dog : Animal()
}

fun test(color: Animal) =
    when (color) {
        is Animal.Cat -> "cat"
        is Animal.Dog -> "dog"
//      else -> "else"//可以省略else分支
    }

注意:sealed修饰的类隐含的这个类是open的,所以不需要显示的添加open修饰符。

当你在when表达式中使用的sealed类创建一个新的子类,when表达式会编译报错,需要也新增一个子类分支。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值