类定义
Kotlin
使用关键字class
声明类
class Person {
}
如果一个类没有类体,可以省略花括号。
class Person
主构造函数
一个类可以有一个主构造函数,一个或多个次构造函数。
class Person constructor(firstName:String){
}
如果主构造函数没有任何注解
或者可见性修饰符
,可以省略这个constructor
关键字。
class Person (firstName:String){
}
主构造函数不能包含任何的代码。初始化的代码可以放到init
作为前缀的初始化块中。
注意:主构造函数的参数可以在初始化块中使用,也可以在类体内声明的属性初始化器中使用。
class Person (firstName:String){
init {
println("FirstName is $firstName");
}
var name: String = firstName;
}
次构造函数
类也可以声明前缀为constructor
的次级构造函数
class Person {
constructor(parent:Person) {
parent.childen.add(this);
}
}
如果类有主构造函数,每个次构造函数都需要直接或间接地委托给主构造函数。委托到同一个类的另一个构造函数用this关键字。
class Person(val name: String) {
constructor (name: String, age:Int) : this(name) {
// 初始化...
}
}
注意:初始化代码块中的代码实际上会成为主构造函数的一部分。委托给主构造函数会作为次级构造函数的第一条语句,因此所有初始化代码块中的代码都会在次构造函数体之前执行。即使该类没有主构造函数,这种委托也会隐式发生,并且仍会执行初始化块。
class Person (firstName: String){
init {
println("FirstName is $firstName");
}
constructor(firstName: String,lastName: String) : this(firstName) {
println("firstName is $firstName,lastName is $lastName");
}
}
val person = Person("W","M");
output:
FirstName is W
firstName is W,lastName is M
如果一个非抽象类没有声明任何构造函数,它会有一个生成的不带参数的主构造函数。构造函数的可见性是public的。如果你不希望类的构造函数是public,你需要声明一个带有非默认可见性的空的构造函数。
class Person private constructor(){
}
继承
在Kotlin
中所有的类都有一个共同的超类Any
。
将超类型放到冒号之后
class MeiZi (xingGe:String,zhangXiang:String,shengYin:String):Presons(xingGe,zhangXiang,shengYin){
}
class ShuaiGe (xingGe:String,zhangXiang:String,shengYin:String):Presons(xingGe,zhangXiang,shengYin) {
}
open class Presons constructor(var xingGe:String,var zhangXiang:String,var shengYin:String){
init {
println("New 了一个${this.javaClass.simpleName}, ta性格: $xingGe,长相: $zhangXiang,声音: $shengYin");
}
}
如果派生类有一个主构造函数,其基类型必须用基类的主构造函数参数就地初始化。
如果派生类没有主构造函数,那么每个次构造函数,必须使用super关键字初始化其基类型,或委托给另一个构造函数做到这一点。
注意:在这种情况下,不同的次构造函数可以调用基类型的不同的构造函数。
class MyView : View {
constructor(ctx: Context) : super(ctx)
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}
覆盖方法
如果父类中的方法没有标注open
,则子类中不允许定义相同签名的函数
子类重写父类的方法,子类方法的前面必须加上override关键字
标记为override的成员本身就是开放的,也就是说,它可以在子类中覆盖。如果你想禁止再次覆盖,使用final关键字
open class Shape {
open fun draw(){};
fun fill(){};
}
class Circle : Shape(){
override fun draw(){};
}
class Rectangle : Shape() {
final override fun draw() {}
}
覆盖属性
属性覆盖和方法覆盖类似,在父类中声明然后在派生类中重新声明的属性必须override
开头,并且它们必须具有兼容的类型
open class Shape {
open val vertexCount:Int = 0;
}
class Circle : Shape(){
override val vertexCount:Int = 8;
}
你可以用一个var
属性覆盖一个val
属性,但反之则不行。因为一个val
属性本质上声明了一个get
方法,而将其覆盖为var
只是在子类中额外声明一个set
方法。
派生类初始化顺序
在构造派生类的新实例的过程中,第一步完成其基类的初始化,因此发生在派生类的初始化运行逻辑之前。
设计一个基类时,应该避免在构造函数,属性初始化器以及init
块中使用open
成员。
调用超类实现
派生类中的代码可以使用super
关键字调用其父类的函数与属性。
在一个内部类中访问外部类的父类,可以通过由外部类名限定的super
关键字来实现。
super@Outer
覆盖规则
如果一个类从它的直接超类继承相同成员的多个实现,它必须覆盖这个成员,并提供自己的实现。为了表示采用从哪个父类型继承的实现,使用由尖括号中父类型名限定的super
,如super<Base>
。
open class Rectangle {
open fun draw() { /* …… */ }
}
interface Polygon {
fun draw() { /* …… */ } // 接⼝成员默认就是“open”的
}
class Square() : Rectangle(), Polygon {
// 编译器要求覆盖 draw():
override fun draw() {
super<Rectangle>.draw() // 调⽤ Rectangle.draw()
super<Polygon>.draw() // 调⽤ Polygon.draw()
}
}
网友评论