与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表达式会编译报错,需要也新增一个子类分支。
本文深入探讨了Kotlin语言的特性,包括与Java的不同之处,如默认final和public的声明,内部类与嵌套类的区别,以及open、final、abstract修饰符的使用。同时,文章详细介绍了可见性修饰符、密封类的概念,以及它们如何影响类和接口的实现。

2060

被折叠的 条评论
为什么被折叠?



