【Kotlin学习】类、对象和接口——定义类继承结构

定义类继承结构

kotlin中的接口

下图声明了一个拥有名为click的单抽象方法的接口,所有实现该接口的非抽象类都要提供这一方法的实现

在这里插入图片描述

kotlin使用冒号代替了extends和implements关键字,和java一样,一个类可实现多个接口但只能继承一个类

在这里插入图片描述

在kotlin中使用override修饰符是强制要求的,这会避免先写出实现方法在添加抽象方法造成的意外重写

接口的方法可以有一个默认实现,在Java8中需要你在这样的实现上标注default关键字,而kotlin没有特殊的注解,只需要提供一个方法体

在这里插入图片描述

现在再定义一个Focusable接口,其中同样实现了一个showOff方法

在这里插入图片描述

当你的类实现这两个接口时,不会使用任何一个实现,编译器会要求你提供你自己的实现

在这里插入图片描述

修改MyButton类如下

在这里插入图片描述

要调用一个继承的实现,可以使用super关键字,但是选择一个特定实现的语法是不同的,在java中是Clickable.super.showOff(),而在kotlin中是super< Clickable>.showOff()

在Java中实现包含方法体的接口

Kotlin1.0是以Java 6为目标设计的,并不支持接口中的默认方法,因此它会把每个带默认方法的接口编译成一个普通接口和一个将方法体作为静态函数的类的结合体

open、final、abstract修饰符:默认为final

在Java中允许你创建任意类的子类并重写任意方法,除非显式调用了final关键字进行标注。对基类进行修改会导致子类不正确的行为,这就是所谓的脆弱的基类问题,因为基类代码的修改不再符合在其子类中的假设。基类的任何修改都有可能导致子类出现与其之外的行为改变。

在java中类和方法默认都是open的,在kotlin中类和方法默认都是final的。

如果你想允许创建一个类的子类,则要使用open修饰符来标示这个类,还要给每一个可以重写的属性和方法添加open修饰符

在这里插入图片描述

如果你重写了一个基类或者接口的成员,重写了的成员同样默认是open的,如果你想阻止你的类的子类重写你的实现,可以显式将重写的成员标为final

在这里插入图片描述

open类和智能转换

类默认final使得在大量场景中的智能转换成为可能,我们之前提到智能转换只能在进行类型检查后没有改变过的变量上起作用,对于一个类来说,这意味着智能转换只能在val类型并且没有自定义访问器的类属性上使用。这个前提意味这属性必须是final的,否则入股一个子类可以重写属性并定义一个自定义的访问器将会打破智能转换的关键前提

在kotlin中,可以将一个类声明为abstruct的,这种类不能被实例化。它通常包含一些没有实现并且必须在子类重写的抽象成员。抽象成员始终是open的,所以不需要显式使用open
在这里插入图片描述

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

可见性修饰符:默认为public

kotlin中和java几乎一样,但是默认情况不一样,kotlin默认是public。
而且提供了一个新修饰符:internal(只在模块内部可见),一个模块就是一组一起编译的kotlin文件,有可能是一个IDEA模块、一组使用调用Ant任务进行编译的文件等等。
kotlin还允许在顶层声明中使用private,包括类、函数、属性,这些声明就会只在声明它们的文件中可见

可见性修饰符类成员顶层声明
public所有地方可见所有地方可见
internal模块中可见模块中可见
protected子类中可见
private类中可见文件中可见

在这里插入图片描述

kotlin禁止从public函数giveSpeech去引用低可见的类型TalkativeButton(internal)。通用规则:类的基础类型和类型参数列表中用到的所有类,或者函数的签名都有与这个类或者函数本身相同的可见性。

注意protected修饰符在java和kotlin的不同,在java中可以从同一个包中访问protected成员,但kotlin不允许,在kotlin中只允许其成员在类和它的子类中可见

注意类的扩展函数不能访问它的private和protected成员

kotlin的可见性修饰符和java

kotlin的public、protected、private修饰符在编译成java字节码时会被保留。唯一的例外是private类:这种情况会被编译成包私有声明。

一个模块通常会由多个包组成,并且不同模块可能会包含来自同一个包的声明,因此internal修饰符在字节码中会变成public,这就解释了为什么有时能从java代码中访问一些你不能从kotlin中访问的东西

类的internal成员名字会被破坏

在kotlin中一个外部类不能看到其内部/嵌套类中的private成员

内部类和嵌套类:默认是嵌套类

在kotlin中可以在另一个类中声明一个类,这样做在封装一个辅助类或者把一些代码放到靠近它被使用的地方时非常有用。但区别于Java,kotlin的嵌套类不能访问外部类的实例,除非你特别地作出了要求。

实例
声明一个包含可序列化状态的视图

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

可以看到我们试图返回一个实现了State接口的ButonState,在kotlin中可行,在java中这样的写法会报错,因为在java中ButtonState类隐式地存储了它的外部MyButton的引用,而MyButton是不能被序列化的,它的引用破坏了ButtonState的序列化。要修复它需要声明ButtonState类为static,这个嵌套类就会删除包围它的类的隐式引用。kotlin中没有显式修饰符的嵌套类和java中的static嵌套类是一样的。要把它变成一个内部类来持有一个外部类的引用的话要使用inner修饰符

类A在另一个类B声明在Java中在Kotlin中
嵌套类(不存储外部类的引用)static class Aclass A
内部类(存储外部类的引用)class Ainner class A

在kotlin中引用外部类实例的语法也和java不同,需要用this@Outer从Inner类访问Outer类

在这里插入图片描述

密封类:定义受限的类继承结构

回顾在kotlin基础篇章中的例子

在这里插入图片描述

在when表达式中处理所有可能的子类固然方便,但是必须提供一个else分支来处理没有任何其他分支能匹配的情况。总是不得不添加一个默认分支很不方便,更重要的是如果你添加了一个新的子类,编译器并不能发现有地方改变了,如果你忘记添加新分支那么就会有bug。

kotlin为此提供了一个解决方案:sealed类。

为父类添加sealed修饰符,对可能创建的子类做出严格的限制,所有的直接子类必须嵌套在父类中

在这里插入图片描述

密封类是不能在类外部拥有子类的,如果你在when表达式中处理所有sealed类的子类,就不需要再提供默认分支。sealed修饰符隐含的这个类是一个open类,不再需要显式地添加open修饰符。

我们不能声明sealed接口,因为编译器不能保证任何人都不能在java代码中实现这个接口

在kotlin1.0中,sealed功能是相当严格的,所有子类必须是嵌套地,且子类不能创建为data类。1.1中解除了这些限制并允许在同一文件地任何位置定义sealed类的子类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值