类
Kotlin中使⽤关键字 class 声明类
class Fruit {
//定义一个水果Fruit类
}
类声明由类名、类头(指定其类型参数、主构造函数等)以及由花括号包围的类体构成。类头与类体都是可选的;如果⼀ 个类没有类体,可以省略花括号。
class Fruit
构造函数
在 Kotlin 中的⼀个类可以有1个主构造函数以及N(N>=0)个次构造函数。主构造函数是类头的⼀部分:它跟在类名后面,并可携带参数(也可没有)如下
class Fruit constructor(var name:String){
//定义带有主构造函数的类
}
如果主构造函数没有任何注解或者可⻅性修饰符,可以省略这个 constructor 关键字。如
class Fruit(var name:String){
//定义一个水果Fruit类
}
主构造函数不能包含任何的代码。初始化的代码可以放到以 init 关键字作为前缀的初始化块(initializer blocks)中。
class Fruit (var name:String){
//定义一个水果Fruit类
init {
println("初始化的代码可以放在init代码块中$name")
}
}
主构造函数的参数可以在初始化块init{}中使用,也可以在类体内声明的属性初始化器中使用:比如我们定义一个name属性,把主函数的参数值赋值给他
class Fruit (var name:String){
//定义一个水果Fruit类
init {
println("初始化的代码可以放在init代码块中$name")
}
var mName = name //主构造函数值赋值给属性mName
}
事实上,声明属性以及从主构造函数初始化属性,Kotlin 有简洁的语法:
class Fruit (val name:String,var age:Int){
}
与普通属性⼀样,主构造函数中声明的属性可以是可变的(var)或只读的(val)。
如果主构造函数有注解或可⻅性修饰符,这个 constructor 关键字是必需的,并且这些修饰符在它前⾯:
class Fruit @xxx constructor(val name:String,var age:Int){
}
次构造
类也可以声明前缀有 constructor的次构造函数:
次构造函数在类内部
class Fruit (val name:String,var age:Int){
//定义一个水果Fruit类
constructor( name:String, age:Int, address:String) : this(name,age)
}
当类中有主构造函数的时候,我们定义的次构造函数需要委托给主构造函数,可以直接委托,也可以通过别的次构造函数间接委托,委托到同一个类的其他构造函数用this关键字即可:如上代码示例
主构造函数是没有函数体的,初始化块init{}实际上就是主构造函数的一部分,可以被当成主构造函数的函数体的。如果没有主构造函数,这种委托会隐式发生,并且也会执行初始化块的。
class Fruit{
init {
println("我是初始化块,虽然我没有主构造函数,在初始化的时候我也会执行的")
}
constructor( name:String, age:Int) {
}
}
fun main() {
var fruit = Fruit("Kotlin",18)
}
控制台输入:
我是初始化块,虽然我没有主构造函数,在初始化的时候我也会执行的
执行上面的代码,通过次构造函数我们创建了Fruit的一个实例,在创建的时候,也执行了init{}代码块
如果一个非抽象类没有任何构造函数,他会有一个不带参数的主 构造函数,构造函数的默认可见性是public,你可以用private声明一个非可见性的主构造函数
class Fruit private constructor(){
init {
println("我是初始化块,虽然我没有主构造函数,在初始化的时候我也会执行的")
}
}
如果主构造函数的所有的参数都有默认值,编译器会⽣成 ⼀个额外的⽆参构造函数,它将使⽤默 认值。这使得 Kotlin 更易于使⽤像 Jackson 或者 JPA 这样的通过⽆参构造函数创建类的实例的库。
class Fruit (val name: String = "xx")
实例创建
要创建⼀个类的实例,我们就像普通函数⼀样调⽤构造函数:不需要使用new关键字 比如我们创建上面的水果类的实例
var fruit = Fruit("Kotlin")
类成员
一个完整的类可以包含如下N个成员
- 构造函数与初始化块
- 函数
- 属性
- 嵌套类与内部类
- 对象声明
抽象类
在一个的类的签名使用abstract修饰,这个类就被定义成了抽象类了,抽象成员在抽象类中可以不用实现。需要注意的是,我们并不需要⽤ open 标注⼀个抽象类或者函数⸺因为这不⾔⽽喻。
我们可以用一个抽象成员覆盖一个非抽象的开放成员
比如类A有一个a方法,抽象类B继承了A,在B中也定义了方法a进行覆盖,我们可以把a用abstract修饰
abstract class B :A{
abstract override fun a(){
}
}