• 一、类
  • 1.1 类的声明
  • 1.2 构造函数
  • 1.3 类实例的创建
  • 1.4 类成员的组成
  • 二、继承
  • 2.1. 构造
  • 2.2 方法的覆盖
  • 2.3 属性的覆盖
  • 2.4 抽象类
  • 2.5 伴生对象



一、类

1.1 类的声明

  1. 类使用 class 关键字声明
  2. Kotlin中的类,默认都是 public final 类型的;
class Parent {} 
class Children //如果类中没有类体,则花括号可以省略

// ---------- 编译后的字节码如下 ------------
public final class Parent {}
public final class Children {}

1.2 构造函数

在Kotlin中,可以有一个主构造函数和多个次构造函数,主构造函数在类头;

主构造函数 & 次构造函数

// 1.如果主构造函数中没有任何 "注解" 或 "可见性修饰符",则 constructor 关键字可以省略
class Parent constructor(name: String) {}
class Parent(name: String) {}
// 有修饰符,注解; constructor不能省略
class Parent public @Inject constructor(name: String) {}

/*
 * 2.在Java中,构造方法中可以进行代码初始化;
 * Kotlin中,主构造函数中不能包含任何代码,但是提供了init{...}方法体
 */
class Parent(name: String) {
    val name: String

    init{ // 主构造的参数可以直接在初始化块 init 中使用
        this.name = name  
    }
}

/*
 * 3.主构造方法中的参数,可以在初始化块init中使用,也可以在类体中声明的属性初始化器中使用;
 * 
 */
class Parent(name: String) {
    //var name: String = name.toUpperCase() //在属性初始化器中使用主构造参数
    val name: String

    init{
        this.name = name  //在初始化块init中使用主构造参数
    }
}
// 在主构造函数中,使用 val 或者 var 声明类中的属性和主构造函数中的属性,在类中任何地方都可以使用
class Parent(val name: String) {
    init {
        print("name = $name")
    }

    fun test() {
        print("name = $name")
    }
}

/*
 * 4. 如果类有主构造函数,每个次构造函数需要委托给主构造函数;
 * 1)可以直接委托,也可以通过其他次构造函数间接委托;
 * 2)委托到通一个类的另一个构造函数使用 this 即可;
 */
class Parent(name: String) {
    var name: String
    var age: Int? = null

    init {
        this.name = name
    }

    constructor(name: String, age: Int): this(name) {// 使用this指引到主构造
        this.age = age
    }
}

// 5.如果主构造函数的所有参数都有默认值,则编译器会生成一个额外的无参构造(默认构造)
class Parent constructor(name: String = "Elson") {

1.3 类实例的创建

val parent = Parent("Elson") //没有Java中的new关键字

1.4 类成员的组成

  • 构造函数
  • 初始化块
  • 函数
  • 属性
  • 嵌套类和内部类
  • 对象声明

二、继承

在Java中,所有类的默认超类是super
在Kotlin中,所有类的默认超类是Any,该类只有toString()、equals()、hashCode() 三个方法;

2.1. 构造

  1. 子类中含有主构造函数
open class Parent(name: String):AnkoLogger {
    var name: String
    var age: Int? = null

    init {
        this.name = name
        info("parent  ... init ")
    }

    constructor(name: String, age: Int):this(name) {
        this.age = age
        info("parent  ... constructor ")
    }
}

// 子类有主构造函数时,则其每个次要构造函数必须使用 super 关键字初始化其基类;或者委托给另一个构造函数执行;
class Child(name: String): Parent(name) {
    private var sex: String?=null
    // 这里使用 this 调用主构造函数进行初始化
    constructor(name: String, age: Int) : this(name) {
        this.age = age
        info("child  ... constructor ")
    }
    // 这里使用 this 间接调用(先调用次要构造,后调用主构造)主构造函数进行初始化
    constructor(name: String, age: Int, sex: String) : this(name, age) {
        this.sex = sex
        info("child  ... constructor ")
    }

    init {
        info("child  ...  init")
    }
}
  1. 子类中不含有主构造函数
// class类默认是final类型的,不能被继承,所以需要使用 open 关键字让父类可以被继承;
open class Parent(name: String):AnkoLogger {
    var name: String
    var age: Int? = null

    init {
        this.name = name
        info("parent  ... init ")
    }

    constructor(name: String, age: Int):this(name) {
        this.age = age
        info("parent  ... constructor ")
    }
}
// 没有主构造函数,则其每个次要构造函数必须使用 super 关键字初始化其基类;或者委托给另一个构造函数执行;
class Child: Parent {
    private var sex: String?=null
    // 这里可以直接调super(name, age),当前是作演示,所以调用super(name);
    constructor(name: String, age: Int) : super(name) {
        this.age = age
        info("child  ... constructor ")
    }

    constructor(name: String, age: Int, sex: String) : super(name, age) {
        this.sex = sex
        info("child  ... constructor ")
    }

    init {
        info("child  ...  init")
    }
}

执行代码:Child(“name”, 18, “M”)
打印结果:
parent … init
parent … constructor
child … init
child … constructor

2.2 方法的覆盖

关键字:open 、override

open class Paren(name: String): AnkoLogger {
    var name: String

    init {
        this.name = name
    }
    // 通过 open 关键字使方法可以被子类重写
    open fun play() {
        info("parsent name = $name")
    }
}

class Child(name: String): Parent(name) {
    // 通过 override 关键字重写父类方法
    override fun play() {
        //super.play()
        info("child name = $name")
    }
}

2.3 属性的覆盖

属性覆盖和方法覆盖类似,可以用 var 属性覆盖一个 val 属性,反之则不行;
关键字:open 、override

open class Parent {
    open val name: String get {...}
}

class Child: Parent() {
    override val name : String = ...
}

2.4 抽象类

可以使用一个抽象的成员覆盖一个非抽象的 open 成员

open class Parent {
    open fun play() {}
}
abstract class Child : Parent() {
    override abstract fun play()
}

2.5 伴生对象

Kotlin中没有静态方法,伴生对象可以实现同样的效果,通过 类名.方法名() 调用;