美文网首页Kotlin
Kotlin类与继承、属性

Kotlin类与继承、属性

作者: 漆先生 | 来源:发表于2021-03-26 09:34 被阅读0次

一、类

Kotlin 中使⽤关键字 class 声明类。类声明由类名、类头(指定其类型参数、主构造函数等)、类体构成。
类头与类体都是可选的;如果⼀ 个类没有类体,可以省略花括号。

class Empty//省掉了类头、类体

二、构造函数

⼀个类可以有⼀个主构造函数以及⼀个或多个次构造函数

1.主构造函数

  • 主构造函数没有任何注解或者可⻅性修饰符,可以省略这个 constructor 关键字。
  • 主构造函数不能包含任何的代码。初始化的代码可以放到以 init 关键字作为前缀的初始化块(initializer blocks)中。
  • 初始化块与属性初始化器的执行顺序按照类体中的顺序
  • 主构造的参数可以在初始化块和属性初始化器中使用
  • 主构造函数中声明的属性可以是可变的(var)或只读的(val)。
class InitOrderDemo(val lastName: String, var age: Int) {
    val firstProperty =
        "First property: $lastName".also(::println)

    init {
        println("First initializer block that prints ${lastName}")
    }

    val secondProperty =
        "Second property: ${lastName.length + age++}".also(::println)

    init {
        println("Second initializer block that prints ${lastName.length + age}")
    }
}

2.次构造函数

在类体中用constructor声明。

  • 如果类有⼀个主构造函数,每个次构造函数需要委托给主构造函数,使用this,可以直接委托或者通过别的次构造函数间接委托。
  • 初始化块会成为主构造函数的⼀部分。委托给主构造函数会作为次构造函数的第⼀条语句,因此所有初始化块与属性初始化器都会在次构造函数体之前执行。
  • 即使该类没有主构造函数,这种委托仍会隐式发生,并且仍会执行初始化块
class Person(val name: String) {
    var children: MutableList<Person> = mutableListOf()

    constructor (name: String, parent: Person) : this(name) {
        parent.children.add(this)
    }
}

class Constructors {
    init {
        println("Init block")
    }

    constructor(i: Int) {
        println("Constructor")
    }
}

另外,⼀个非抽象类没有声明任何(主或次)构造函数,它会有⼀个生成的不带参数的主构造函数。可见性默认public
如果主构造函数的所有的参数都有默认值,编译器会生成 ⼀个额外的无参构造函数

class Customer(val customerName: String = "")

三、创建类的实例

像普通函数⼀样调⽤构造函数,不需要new

1.类成员

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

2.继承

在 Kotlin 中所有类都有⼀个共同的超类 Any(隐式继承),类似java的Object

  • 默认情况下,Kotlin 类是最终(final)的,用 open 关键字标记才能被集成
  • 类头中把超类型放到冒号之后
  • 如果派生类有⼀个主构造函数,其基类必须用派生类主构造函数的参数就地初始化。
open class Base(p: Int) 
class Derived(p: Int) : Base(p)

派生类没有主构造函数,那么每个次构造函数必须使用 super 关键字初始化其基类型,或委托给另⼀个构造函数做到这⼀点

class MyView : View {
    constructor(context: Context) : super(context)
    constructor(context: Context, attr: AttributeSet) : this(context)
}

3.覆盖方法

  • 基类和被覆盖方法否需要加上open标记
  • 覆盖方法加上override标记
  • 禁止再次覆盖,使⽤final关键 字
open class Rectangle() : Shape() {
    final override fun draw() { /*……*/ }
}

4.覆盖属性

属性覆盖与方法覆盖类似;在超类中声明然后在派生类中重新声明的属性必须以 override 开头,并且它们必须具有兼容的类型。

  • 每个声明的属性可以由具有初始化器的属性或者具有 get 方法的属性覆盖
  • 你也可以用⼀个 var 属性覆盖⼀个 val 属性,但反之则不行
interface Shape {
    val vertexCount: Int
}

class Rectangle(override val vertexCount: Int = 4) : Shape

class Polygon : Shape {
    override var vertexCount: Int = 0 // 以后可以设置为任何数
}

5.派生类初始化顺序

先完成其基类的初始化,再完成派生类的初始化。
基类构造函数执行时,派生类中声明或覆盖的属性都还没有初始化。如果在基类初始化逻辑中(直接或通过 另⼀个覆盖的 open 成员的实现间接)使用了任何⼀个这种属性,那么都可能导致不正确的行为或运行时故障。设计⼀ 个基类时,应该避免在构造函数、属性初始化器以及 init 块中使用 open 成员

6.调用超类实现

  • 用 super 关键字调用其超类的函数与属性访问器的实现
  • 在⼀个内部类中访问外部类的超类,可以通过由外部类名限定的 super 关键字来实现:super@外部类的类名,如super@Outer

7.覆盖规则

如果⼀个类从它的直接超类继承相同成员的多个实现,为了表示采用从哪个超类型继承的实现,我们使用由尖括号中超类型名限定的 super,如 super<Base> :

open class Rectangle {
    open fun draw() { /* …… */ }
}

interface Polygon {
    fun draw() { /* …… */ }// 接⼝成员默认就是“open”的
}

class Square() : Rectangle(), Polygon {
    override fun draw() {
        super<Rectangle>.draw() // 调用 Rectangle.draw()
        super<Polygon>.draw() // 调用 Polygon.draw() }
    }
}

8.抽象类

用abstract声明,不再需要open

9.伴生对象

companion关键字标记,该伴生对象的成员可通过只使用类名作为限定符来调用:

class MyClass {
    companion object Factory {
        fun create(): MyClass = MyClass()
    }
}
val instance = MyClass.create()

四、属性

1.声明属性

属性既可以用关键字 var 声明为可变的,也可以用关键字 val 声明为只读的。

2.Getters 与 Setters

声明⼀个属性的完整语法如下,其初始器(initializer)、getter 和 setter 都是可选的

    var <propertyName>[: <PropertyType>] [= <property_initializer>] 
        [<getter>] 
        [<setter>]

用了幕后字段field,需要使用初始化器。没用幕后字段使用初始化器,编辑器报错:Initializer is not allowed here because this property has no backing field
⾃定义的 getter setter 如下所示:

var stringRepresentation: String
    get() = this.toString()
    set(value) {
        setDataFromString(value) // 解析字符串并赋值给其他属性
    }

var counter = 0
    set(value) {
        field = if (value >= 0) value else -1
    }

1.编辑器常量

可以使用 const 修饰符将其标记为编译期常量。const var 等于public static final 默认是pubic,可以指定

  • 位于顶层或者是 object 声明 或 companion object 的⼀个成员
  • 以 String 或原生类型值初始化
  • 没有⾃定义 getter

2.延迟初始化属性与变量

lateinit 修饰符标记该属性,只能用于在类体中的属性,.isInitialized,判定属性或者变量是否被初始化

相关文章

网友评论

    本文标题:Kotlin类与继承、属性

    本文链接:https://www.haomeiwen.com/subject/icurhltx.html