本文是对<<Kotlin in Action>>
的学习笔记,若是须要运行相应的代码能够访问在线环境 try.kotlinlang.org,这部分的思惟导图为: java
Kotlin
的接口能够包含如下两种类型的方法:框架
Kotlin
接口使用 interface 关键字来声明,全部实现这个接口的非抽象类都须要实现接口中定义的抽象方法。Kotlin
在类名后面使用 冒号 代替了Java
中的extends
和implements
关键字,一个类能够实现多个接口,可是只能继承一个类。override
修饰符用来标注被重写的父类或者接口的方法和属性,而且是 强制要求 的。下面的例子中定义了一个接口,并演示了如何实现该接口,以及接口中定义的抽象方法: ide
咱们能够给接口的方法提供一个默认的实现,定义的方法和普通函数相同。 函数
当须要调用一个继承的实现,可使用与Java
相同的关键字 super,并在后面的尖括号中指明父类的名字,最后是调用的方法名: 学习
Kotlin
中,类和方法默认都是final
的,若是想容许建立一个类的子类,须要使用open
修饰符来标示这个类,此外还须要给每个容许被重写的属性或方法添加open
修饰符。open
的,若是想改变这一行为,能够显示地将重写的成员标注为final
。咱们能够将一个类声明为abstract
,这种类不能被实例化,一个从抽象类一般包含一些没有实现而且必须在子类重写的抽象成员:this
abstract
的,不必定要加上关键字,其访问性始终是open
的。final
的,若是须要重写,那么须要加上open
修饰符。open
、final
和abstract
这三个访问修饰符都 只适用于类,不能用在接口 当中:spa
open
:用于声明一个类能够被继承,或者方法能够被子类重写。final
:不容许类被继承,或者不容许方法被重写。abstract
:声明抽象类,或者抽象类中的抽象方法。当咱们须要重写方法时,必须加上override
修饰符。设计
Kotlin
的可见性修饰符包括如下四种:3d
修饰符 | 类成员 | 顶层声明 |
---|---|---|
public | 全部地方可见 | 全部地方可见 |
internal | 模块中可见 | 模块中可见 |
protected | 子类中可见 | --- |
private | 类中可见 | 文件中可见 |
Java
和Kotlin
在可见性上的区别包括如下几点:code
Java
中默认的可见性是包私有的,而在Kotlin
中,默认的可见性是public
的。Kotlin
用internal
做为包可见的替代方案,它表示“只在模块内部可见”。Kotlin
容许在顶层声明中使用private
可见性,包括类、函数和属性,这些声明就只在声明它们的文件中可见,这是隐藏子系统实现细节的很是有用的方式。private
和protected
成员。Kotlin
中,一个外部类不能看到其内部类中的private
成员。在Kotlin
中,若是咱们像Java
同样,在一个类的内部定义一个类,那么它并非一个 内部类,而是 嵌套类,区别在于嵌套类不会持有外部类的引用,也就是说它其实是一个静态内部类:
inner
修饰符,而且访问外部类时,须要使用
this@{外部类名}
的方式。
以前在介绍when
表达式的时候,咱们用了一个表达式的例子,Num
和Sum
继承于基类Expr
,分别表达数字和两个表达式之和,而对于不属于Expr
的子类,咱们须要提供额外的else
操做符。
Expr
添加了一个新的子类,编译器并不能发现有地方改变了。若是忘记了添加一个新分支,就会选择默认的选项,这有可能致使潜在的
bug
。
Kotlin
为这个问题提供了一个解决方案:sealed
类。为父类添加一个sealed
修饰符,对可能建立的子类作出严格的限制,全部的直接子类必须嵌套在父类中。以前的例子修改以下:
when
表达式中已经处理了全部
Expr
的子类,就再也不须要提供默认的分支,假如这时候咱们给
Expr
添加一个新的子类
Multi
,可是不修改
when
中的逻辑,那么就会致使编译失败:
Expr
类有一个只能在类内部调用的
private
构造方法,你也不能声明一个
sealed
接口,由于若是这样作,
Kotlin
编译器不能保证任何人都不能在
Java
代码中实现这个接口。
在Java
中,一个类能够声明一个或多个构造方法,Kotlin
则将构造方法分为两类:
假设,咱们须要定义一个包含只读nickname
属性的User
类,最简单的方式为:
nikename
。用于完成上面这两个功能的最明确的代码以下所示:
constructor
:用来开始一个主构造方法和从构造方法的声明。init
:引入一个初始化块语句,这种语句块包含了在类被建立时执行的代码,并会与主构造方法一块儿使用,由于主构造方法有语法限制,这就是为何要使用初始化语句块的缘由。在上面的例子中有几个能够简化的点:
nikename
的声明结合,所以能够去掉init
语句。constructor
关键字。val
关键字加在参数前的方式来进行简化。通过了以上三点,就会获得最前面简化后的结果。
对于构造方法,也能够采用以前在 Kotlin 知识梳理(2) - 函数的定义与调用 中介绍的 命名参数 和 默认参数值 的技巧,若是全部的构造方法都有默认值,编译器会生成一个额外的不带参数的构造方法来使用全部的默认值。
在Java
中,若是父类定义了一个构造方法,那么在子类的构造方法中,必需要经过super
方法初始化父类,例如:
//父类。
public class User {
private String nikeName;
User(String nikeName) {
this.nikeName = nikeName;
}
}
//子类。
public class TwitterUser extends User {
public TwitterUser(String nikeName) {
super(nikeName);
}
}
复制代码
而在Kotlin
中,能够经过在基类列表的父类引用中提供父类构造方法参数的方式来作到这一点:
private
,咱们对上面的例子进行修改:
Kotlin
有为主构造方法设计的简洁的语法。
大多数在Java
中须要重载构造方法的场景都被Kotlin
支持命名参数和参数默认值的语法所覆盖了。
而当咱们须要扩展一个框架来提供多个构造方法,以便于经过不一样的方式来初始化类的时候,就会须要用到从构造方法,从构造方式使用constructor
方法引出,例以下面的代码:
若是想要扩展这个类,能够声明一样的构造方法,并使用super
关键字调用对应的父类构造方法:
若是想要从一个构造方法中,调用你本身的类的另外一个构造方法,那么可使用this
关键字:
super
关键字)或者委托给另外一个这样作了的构造方法(经过
this
关键字),也就是说,每一个从构造方法必须以一个朝外的箭头开始,而且结束于任意一个基类构造方法,就像上面例子中
Button
的带有两个参数的从构造方法所作的那样。
在Kotlin
中,接口能够包含抽象属性的声明:
getter
来获取,接口自己并不包含任何状态,所以只有实现这个接口的类在须要的时候会存储这个值。
下面是三个例子:
PrivateUser
:直接在主构造方法中声明了这个属性,这个属性实现了来自于User
的抽象属性,因此要标记为override
。SubscribingUser
:经过一个自定义的getter
实现,这个属性没有一个支持字段来存储它的值,它只有一个getter
在每次调用时从email
中获得昵称。FacebookUser
:在初始化时,将nickname
属性与值关联。接口除了能够声明抽象属性外,还能够包含具备getter
和setter
的属性,只要它们没有引用一个支持字段(支持字段须要在接口中存储状态,而这是不容许的):
email
:必须在子类中重写。nickname
:有一个自定义的getter
,能够被子类继承。如今,咱们已经学习了两种属性的用法:
如今,咱们结合以上两种,来实现一个既能够存储值,又能够在值被访问和修改时提供额外逻辑的属性:
address
就是
有支持字段的属性,它和
没有支持字段的属性 的区别在于:
field
,支持字段就不会被呈现出来。访问器的可见性默认与属性的可见性相同,可是若是须要能够经过在get
和set
关键字前放置可见性修饰符的方式来修改它,例如在下面的例子中,咱们将setter
的可见性修改成private
: