一、类的声明
1、关键字
声明类的关键字为class
二、类的构造函数
- 在Kotlin中,允许有一个主构造函数和多个二级构造函数(次构造函数)。其中主构造函数是类头的一部分。
- 关键字或者构造函数名:constructor(参数)
主构造器
主构造器中不能包含任何代码,初始化代码可以放在初始化代码段中,初始化代码段使用 init关键字作为前缀。
class Person constructor(firstName: String) {
init {
println("FirstName is $firstName")
}
}
次构造函数
类也可以有二级构造函数,需要加前缀 constructor:
class Person {
constructor(parent: Person) {
(this)
}
}
如果类有主构造函数,每个次构造函数都要,或直接或间接通过另一个次构造函数代理主构造函数。在同一个类中代理另一个构造函数使用 this 关键字:
class Person(val name: String) {
constructor (name: String, age:Int) : this(name) {
// 初始化...
}
}
主构造函数、次构造函数详解:
open class People {
}
Java 中类是可以默认继承的,但是 Kotlin 不一样。如果想要在 Kotlin 中的类被继承,那么需要使用关键字 open。
class Student : People() {
}
Java 中继承使用 extends,Kotlin 中继承使用 " : " 来处理。Java 中类继承不需要括号, Kotlin 中类继承需要括号。
主构造函数
- 父类无参构造函数
//不带参数 class Student (): People() { }
每个类有个默认不带参数的主构造函数。
主构造函数的特点-> 没有函数体,直接定义在类名后。//带参数 class Student(sno: String, grade: Int) : People() { }
Java 和 Kotlin 一样,子类的构造函数必须调用父类的构造函数。
上面代码中 Student 类初始化主构造函数时候会调用 People 类的无参主构造函数,即使没有参数也不能省略,所以这也是 Kotlin 中继承类有括号的原因。 - 父类有参构造函数
class Student(sno: String, grade: Int, name: String, age: Int) : People(name, age) { }
当父类主构造函数带参数时,由于子类必须实现父类主构造函数,所以可以在子类的主构造函数中加入父类构造函数需要的参数。
如果子类有主构造函数, 则基类必须在主构造函数中立即初始化。
次构造函数
class Student(sno: String, grade: Int, name: String, age: Int) : People(name, age) {
constructor(name: String, age: Int) : this("", 0, name, age) {
}
constructor() : this("", 0) {
}
}
1-> 次构造函数通过 constructor 关键字定义
2-> Kotlin 规定所有次构造函数必须调用主构造函数
- 特殊情况,子类和父类都没有构造函数
class Students : Persons {
constructor(name: String, age: Int) : super(name, age) {
}
}
open class Persons {
constructor(name: String, age: Int) {
}
}
子类没有主构造函数所以不用带括号,同理父类也是一样。
如果子类没有主构造函数,则必须在每一个二级构造函数中用 super 关键字初始化基类,或者在代理另一个构造函数。初始化基类时,可以调用基类的不同构造方法。
实例
/**用户基类**/
open class Person(name:String){
/**次级构造函数**/
constructor(name:String,age:Int):this(name){
//初始化
println("-------基类次级构造函数---------")
}
}
/**子类继承 Person 类**/
class Student:Person{
/**次级构造函数**/
constructor(name:String,age:Int,no:String,score:Int):super(name,age){
println("-------继承类次级构造函数---------")
println("学生名: ${name}")
println("年龄: ${age}")
println("学生号: ${no}")
println("成绩: ${score}")
}
}
fun main(args: Array<String>) {
var s = Student("Runoob", 18, "S12345", 89)
}
//输出结果:
//-------基类次级构造函数---------
//-------继承类次级构造函数---------
//学生名: Runoob
//年龄: 18
//学生号: S12345
//成绩: 89
抽象类
抽象是面向对象编程的特征之一,类本身,或类中的部分成员,都可以声明为abstract的。抽象成员在类中不存在具体的实现。
注意:无需对抽象类或抽象成员标注open注解。
open class Base {
open fun f() {}
}
abstract class Derived : Base() {
override abstract fun f()
}
嵌套类
嵌套类使用 Nested 关键字来表示。
class Outer { // 外部类
private val bar: Int = 1
class Nested { // 嵌套类
fun foo() = 2
}
}
fun main(args: Array<String>) {
val demo = ().foo() // 调用格式:外部类.嵌套类.嵌套类方法/属性
println(demo) // == 2
}
内部类
- 内部类使用 inner 关键字来表示。
- 内部类会带有一个对外部类的对象的引用,所以内部类可以访问外部类成员属性和成员函数。
class Outer {
private val bar: Int = 1
var v = "成员属性"
/**嵌套内部类**/
inner class Inner {
fun foo() = bar // 访问外部类成员
fun innerTest() {
var o = this@Outer //获取外部类的成员变量
println("内部类可以引用外部类的成员,例如:" + )
}
}
}
fun main(args: Array<String>) {
val demo = Outer().Inner().foo()
println(demo) // 1
val demo2 = Outer().Inner().innerTest()
println(demo2) // 内部类可以引用外部类的成员,例如:成员属性
}
类的修饰符
类属性修饰符,标示类本身特性。
abstract // 抽象类
final // 类不可继承,默认属性
enum // 枚举类
open // 类可继承,类默认是final的
annotation // 注解类
访问权限修饰符
private // 仅在同一个文件中可见
protected // 同一个文件中或子类可见
public // 所有调用的地方都可见
internal // 同一个模块中可见