1、类的继承结构
接口
* Kotlin的类和接口与Java的有些地方不一样:
* Kotlin的声明默认是public final的。
* Kotlin嵌套的类默认不是内部类:它没有包含对外部类的隐式引用 等
* Kotlin也一样是使用interface来声明接口
* 如下: 声明一个简单的接口
interface Clickable { fun click() fun longPress() = println("longPress") //接口中的抽象方法也可以有默认的实现,有了默认的是现在之后实现类可以选择性的去重写 }
实现接口:
* Kotlin在类后面加一个冒号来代替了Java的 implements 和 extends 关键字,
* 和Java一样的是,一个类可以实现任意多个接口,但是只能继承一个类.
* 与Java中的 @Override 注解类似,override 修饰符用来标注被重写的父类或者接口的方法和属性,
* 与Java不同的是 override 修饰符是强制要求的,
class Button : Clickable { override fun click() { println("Button is clicked") } }
* Kotlin 接口中的方法也可以有个默认的实现,与Java 8 要求在这样的方法前加default 关键字不同的是:Kotlin 不要加任何多余的关键字
* 只需要提供一个方法体就好了
interface Clickable_0 { fun click() /** * 这个方法提供了一个默认的实现,如果实现这个接口,可以选择重新定义它,也可以直接只用它 */ fun showOff() = println("I‘m Clickable") fun show() = println("show") }
* 下面的Focusable 接口中也有一个方法 showOff ,如果一个类同时实现了 Clickable_0 和 Focusable 俩接口,就必须显示的实现showOff
* 否则会编译错误 Class ‘Button_0‘ must override public open fun showOff(): Unit defined in com.mauiie.kotlin.chapter3ClassObjectInterface.Clickable_0 because it inherits multiple interface methods of it
interface Focusable { fun setFoucus(b: Boolean) { println("I ${if (b) " got " else " lost "} focus.") } fun showOff() = println("I‘m Focusable") fun show() = println(" show !") }
Button_0 同时实现了上面的两个接口:
class Button_0 : Clickable_0, Focusable { override fun click() { println("Button is clicked") } /** * 因为Clickable_0, Focusable 都定义了showOff 方法,所以这里必须显示的实现 */ override fun showOff() { /** * 使用尖括号加上父类型的名字的“super”表示想要调用哪一个父类的的方法(默认实现) * */ super<Clickable_0>.showOff() super<Focusable>.showOff() } override fun show() = super<Focusable>.show() }
open、final、抽象类
* Java的类和方法默认是open的,这样默认子类可以任意修改默认类的默认方法个属性
* Kotlin中的类个方法默认都是final的,这样可以规避“脆弱基因”问题
* 如果你想创建一个类的子类,需要使用open 关键字来修饰这个类,此外需要给每一个可以被重写的属性或方法添加一个open修饰符
* 这个类是open的,所以其它类可以继承它
* 如果你重写了一个基类或者接口的成员(方法),默认它也是open的,如果你不想让子类在重写这个方法,就需要显示的将重写的成员标注为 final 的
open class RichButton : Clickable { /** * 这个方式final的,不能在子类中重写它 */ fun disable() {} /** * 这个方法是open的,可以在子类中重写它 */ open fun animate() {} /** * 这个方法是重写的一个open的方法,并且他本身也是open 的,子类可以重写它 */ override fun click() { println(" RichButton click ") } /** * 这个重写的方法添加了 final,所以子类肯定不能重写它 */ final override fun longPress() { super.longPress() } }
* 在Kotlin中,同Java一样可以声明一个类为abstract的,这种抽象类不能被实例化。
* 一个抽象类通常包含一些没有实现并且必须在子类重写的抽象成员。抽象成员始终是open的,所以不需要显示的使用open修饰符
abstract class Animated { /** * 抽象方法没有被实现,它必须被子类所实现,默认是open的,这里的也可以用open修饰(多此一举) */ abstract fun animate() /** * 抽象类中的非抽象方法默认是final的,但是也可以用open修饰以便子类重写 */ open fun stopAnimating() {} /** * 没有用open修饰的非抽象方法则不能被子类所重写 */ fun animateTwice() {} }
可见性修饰符、内部类
* Kotlin中的可见性修饰符与Java中的类似。可以使用public、protected和private修饰符。
* 但是与Java不同的是Kotlin 默认是public的,Java默认的包私有性Kotlin并没有沿用,Kotlin只把包作为在命名空间里组织代码的一种方式使用,没有将其用作可见性控制。
* 作为替代方案Kotlin提供了一种新的修饰符“internal”,表示“只在模块内部可见”。一个模块就是一组一起编译的Kotlin文件。
* internal可见性的优势在于它提供了对模块实现细节的真正封装。
* 另一个区别就是Kotlin允许在顶层声明中使用private可见性,包括类、函数、和属性。这些声明就会只在声明他们的文件中可见。
internal open class TalktiveButton : Focusable { private fun yell() = println("Hey!") protected fun whisper() = println("Let‘s Talk") }
* 像Java一样,Kotlin 也支持在一个类中直接声明另一个类,区别是在Kotlin 中直接声明在类中的嵌套类不能访问外部类的实例,除非你做出了要求
interface State : Serializable interface View { fun getCurrentState(): State fun restoreState(state: State) {} } /*JAVA 的演示实例请参照 JavaCallTest*/ /** * Kotlin 没有显示修饰符修饰的内部类与Java中的static 嵌套类是一样的,不会持有外部类的引用。 */ class Button2 : View { override fun getCurrentState() = ButtonState() override fun restoreState(state: State) { super.restoreState(state) } class ButtonState : State { } }
* 如果想让他变成内部类就必须加上inner 修饰符,这样才会只有外部类的引用。
* Kotlin中在内部类中引用外部类的语法也与Java不同 使用:this@Outer从内部类去访问外部类
class Outer { inner class Inner { fun getOuterReference(): Outer = this@Outer } }
sealed封闭类
* 为了解决子类可以随便任意的父类而导致无法约束子类的实现类问题。Kotlin推出了sealed关键字 sealed(密封、封闭),
* 为父类添加一个sealed修饰符,对可能创建的子类做出严格的限制。所有的直接子类必须嵌套再父类中。
* 注意 sealed 修饰符隐含的这个类是open的,不要在显示地添加open修饰符
/** * 使用sealed 标记类为封闭的 */ sealed class Expr { //将所有的实现子类作为嵌套类列举出来 class Num(val value: Int) : Expr() class Sum(val left: Expr, val right: Expr) : Expr() }
这样当在when 循环中列举出所有的可能的实现子类之后就不需要在检查默认的分支(因为封闭类已经列举出所有可能的实现子类)
fun eval(e: Expr): Int = when (e) { is Expr.Num -> e.value is Expr.Sum -> eval(e.left) + eval(e.right) }
//!!使用冒号实现接口的时候 直接 :Interface
//!!使用冒号集成父类的时候 直接 :ParentClass()