地址:http://kotlinlang.org/docs/reference/classes.html
日期:2017年 06月 24日 星期六
译者:Linky
在 Kotlin 中,类 使用关键字 class 声明:
class Invoice {
}
类的声明由类名,类头(确定它的类型参数、私有构造函数等)和类体组成,类头 和 类体 是可选的。
如果一个类没有体,花括号可以省略。
class Empty
Kotlin 中,一个类可以有一个主要构造器和一个或多个次要构造器。主要构造器是类头的一部分,
跟在类名之后,类型参数 是可选的。
class Person constructor(firstName: String) {
}
如果主要构造器没有任何注解或者可见的修饰符,关键字 constructor
可以省略
class Person(firstName: String) {
}
注意:构造函数里面不能包含任何代码,初始化代码可以放在初始块中,初始块以 init
关键字为前缀:
class Customer(name: String) {
init {
logger.info("Customer initialized with value ${name}")
}
}
注意到,主要构造器的参数可以在 初始块中引用,它们也可以在属性初始化声明中使用:
class Customer(name: String) {
val customerKey = name.toUpperCase()
}
声明和初始化属性,Kotlin 有一个更简单的语法:(PS : 多个了 val 或者 var 关键字)
class Person(val firstName: String, val lastName: String, var age: Int) {
// ...
}
如果构造函数有注解或者可见的修饰符,那么 constructor
关键字是需要的,修饰符写在它
的前面:
class Customer public @Inject constructor(name: String) { ... }
更多详情查看Visibility Modifiers
一个类也可以声明次要构造器,以 constructor 为前缀:
class Person {
constructor(parent: Person) {
parent.children.add(this)
}
}
如果一个类有主要构造器,那么每个次要构造器都需要委托主要构造器(直接或间接)。
委托另一个构造器可以使用 this 关键字:
class Person(val name: String) {
constructor(name: String, parent: Person) : this(name) {
parent.children.add(this)
}
}
如果一个非抽象类没有声明任何构造器(主要或次要),默认会有一个不带参数的主要构造器,
可见性为 public。如果你不想你的类有一个 public 的构造器,则需要你手动声明:
class DontCreateMe private constructor () {
}
注意:在 JVM 中,如果 主要构造器 的所有参数都有默认值,编译器将会构造一个额外的没有参数的
构造器,并且使用默认值。这个特性使得 Kotlin 在使用 jackson 或者 JPA 等通过无参构造器实例化
类对象的第三方库时变得非常容易。
class Customer(val customerName: String = "")
创建类对象时,直接调用类的构造器,就像它是一个标准的函数一样:
val invoice = Invoice()
val customer = Customer("Joe Smith")
注意到,Kotlin 没有使用 new
关键字
创建嵌套的实例,内部和匿名内部类,可以查看Nested classes
类可以包含
—— 构造器 和 初始化块
—— 函数
—— 属性
—— 嵌套或者内部类
—— 对象声明
Kotlin 中的所有类都有一个共同的父类 Any
class Example // 隐式继承 Any
Any
不是 java.lang.Object
,具体来说,它只有 equals()
, hashCode()
和 toString()
方法,
而没有其他任何成员。你可以查看 Java interoperability获得更多细节。
为了显式地声明一个父类,我们在类头中加个冒号和父类型即可:
open class Base(p: Int)
class Derived(p: Int) : Base(p)
如果类有一个主要构造器,基类必须在那里初始化。
如果类没有主要构造器,那么每个次要构造器必须初始化基类,使用 super
关键字,或者委托
其他构造器这么做。注意到,这种情况下,不同的次要构造器可以调用不同的基类构造器。
class MyView : View {
constructor(ctx: Context) : super(ctx)
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}
open
注解和 java 中的 final
相反:它允许其他类从这个类继承。默认情况下,Kotlin
中的所有类都是 final
的,这主要是借鉴了 Effective java17 章的内容:要么为继承设计好,要么禁止它
就像上面说的,我们争取在 Kotlin 中一切都是那么清晰,不像 java, Kotlin 要求对
可重写的成员进行明确的注解(使用 open):
open class Base {
open fun v() {}
fun nv() {}
}
class Derived() : Base() {
override fun v() {}
}
Derived.v()
需要用 override
注解,否则编译器会报错。如果父类中的方法 Base.nv()
没有声明 open
注解,在子类中定义相同的方法,无论是否有 override
都是不允许的。
在一个 final
类中(没有 open
注解的类),用 open 修饰成员是不被允许的。
一个用 override
标记的成员本身是 open 的。在子类中可以被重写,如果你想禁止再次重写,
可以使用 final
:
open class AnotherDerived() : Base() {
final override fun v() {}
}