美文网首页Android技术知识Android开发Kotlin
4.1.2 open、final 和 abstract 修饰符:

4.1.2 open、final 和 abstract 修饰符:

作者: 无心下棋 | 来源:发表于2018-08-04 15:43 被阅读3次

Java允许你创建任意类的子类并重写任意方法,除非显式地使用 了 final关键字进行标注。这通常很方便.但是也造成了一些问题。
对基类进行修改会导致子类不正确的行为,这就是所谓的脆弱的基类问题,因 为基类代码的修改不再符合在其子类中的假设,如果类没有提供子类应该怎么实现 的明确规则(哪些方法需要被®写及如何重写〉,当事人可能会有按基类作者预期 之外的方式来重写方法的风险。因为不可能分析所有的子类.这种情况下基类是如 此“脆弱任何修改都有可能导致子类出现预期之外的行为改变。

为了防止这种问题,作为优秀Java编程风格最为知名的图书之一,Joshua Bloch的^Effective Javu、(Addison-Wesley. 2008)建议你“要么为继承做好设计并 记录文档,要么禁止这么做”。这意味着所有没有特别需要在子类中被重写的类和 方法应该被显式地标注为final.

Kotlin采用了同样的哲学思想。Java的类和方法默认是open的,而Kotlin中默 认都是final的。

如果你想允许创建一个类的子类,需要使用open修饰符来标示进个类。此外, 需要给每一个可以被重写的属性或方法添加open修饰符。

//这个类是open的:其 他类可以继承它
open class RichButton :Clickable {
    //这个函数是final的,不能 在子类中重写它
    fun disable() {}
    //这个函数是open的:可以 在子类中重写它
    open fun animate() {}
    //这个函数重写了一个open函数并 I且它本身同样是open的
    override fun click() {}
}

注意.如果你重写了一个基类或者接口的成员,璽写了的成员同样默认是 open的。如果你想改变这一行为,阻止你的类的子类重写你的实现,可以显式地 将重写的成员标注为final。

open class RichButton : Clickable {
    //在这里“final”并没有被删减是 因为没有"final"向“override” 意味着是open的
    final override fun click。{}
}    

在Kotlin中,同Java —样,可以将一个类声明为abstract的,这种类不能被实例化。一个抽象类通常包含一些没有实现并且必须在子类重写的抽象成员。抽 象成员始终是open的,所以不需要显式地使用open修饰符:

//这个类是抽象的:不能创建它的实例
abstract class Animated {
    //这个函数 是抽象的:它没有实现必须被子类重写
    abstract fun animate()
    //抽象类中的非抽象函数并不是默认 open的,但是可以标注为open的
    open fun stopAnimating() {
    }
    fun animateTwice() {
    }
}

下面列出了 Kotlin中的访问修饰符,表中的评注适用子类中的修饰符:在接口中,不能使用final, open或者是abstract。接口中的成员始终是open的, 不能将其声明为final的。如果它没有函数体它就是abstract的,但是这个关键 字并不是必需的。

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

讨论完控制继承的修饰符,现在让我们转向另一种类型的修饰符:可见性修饰符。

4.1.3可见性修饰符:默认为public

可见性修饰符帮助控制对代码库中声明的访问。通过限制类中实现细节的可见性,可以确保在修改它们时避免破坏依赖这个类的代码的风险。

总的来说,Kotlin中的可见性修饰符与Java中的类似。同样可以便用public、 protected和private修饰符。但是默认的可见性是不一样的:如果省略了修饰符,声明就是public的。

Java中的默认可见性——包私有,在Kotlin中并没有使用。Kodin只把包作为在命名空间里组织代码的一种方式使用,并没有将其用作可见性控制。

作为替代方案,Kotlin提供了一个新的修饰符 internal,表示“只在模块内部可见”。一个模块就是一组一起编译的Kotlin文件。这有可能是一个Intdlij IDEA模块、一个Eclipse项目、一个Maven或Grade项目或者一组使用调用Ant 任务进行编译的文件。

internal可见性的优势在于它提供了对模块实现细节的真正封装。使用Java 时,这种封装很容易被破坏,因为外部代码可以将类定义到与你代码相同的包中, 从而得到访问你的包私有声明的权限。

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

  • Kotlin的可见性修饰符
修饰符 类成员 顶层声明
public (默认) 所有地方可见 所有地方可见
internal 模块中可见 模块中可见
protected 子类中可见
private 类中可见 文件中可见

Kotlin禁止从public函数去引用低可见的类型。
一个通用的规则是:类的基础类型和类型参数列表中用到的所有类,或者函数的签名都有与这个类或者函数本身相同的可见性。这个规则可以确保你在需要调用函数或者继承一个类时能够始终访问到所有的类型。要解决上面例子中的问题,既可以把函数改为internal的,也可以把类改成public的。

注意,protected修饰符在Java和Kotlin中不同的行为。在Java中,可以从 同一个包中访问一个protected的成员,但是Kotlin不允许这样做。在Kotlin中 可见性规则非常简单,protected成员只在类和它的子类中可见。同样还要注意的是类的扩展函数不能访问它的private和protected成员。

Kotlin的可见性修饰符和Java

Kotlin中的public、protected和private修饰符在编译成Java字节 码时会被保留你从Java代码使用这些Kotlin声明时就如同他们在Java中声明 了同样的可见性唯一的例外是private类:在这种情况下它会被编译成包私 有声明(在Java中你不能把类声明为private)。

但是,你可能会问,internal修饰符将会发生什么? Java中并没有直接与之类似的东西。包私有可见性是一个完全不同的东西:一个模块通常会由多 个包组成,并且不同模块可能会包含来自间一个包的声明因此internal修 饰符在字节码中会变成public

这些Kotlin声明和它们Java翻版(或者说它们的字节码呈现)的对应关系解释了为什么有时你能从Java代码中访问一些你不能从Kotlin中访问的东西。例如,可以从另一个模块的Java代码中访问internal类或顶层声明,抑或从同一个包的Java代码中访问一个protected的成员(与你在Java中做的相似)。

但是注意类的internal成员的名字会被破坏,从技术上讲,internal 成员也是可以在Java中使用的,但是它们在Java代码中看起来很难看,当你从另一个模块继承类时.可以帮助避免在重写时出现出乎意料的冲突.并且避免 意外使用internal类。

另一个Kotlin与Java之间可见性规则的区别就是在Kotlin中一个外部类不能看到其内部(或者嵌套)类中的private成员。

相关文章

网友评论

    本文标题:4.1.2 open、final 和 abstract 修饰符:

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