Kotlin

Kotlin类与继承、属性

2021-03-26  本文已影响0人  漆先生

一、类

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

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

二、构造函数

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

1.主构造函数

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声明。

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

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 class Rectangle() : Shape() {
    final override fun draw() { /*……*/ }
}

4.覆盖属性

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

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.调用超类实现

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,可以指定

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

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

上一篇下一篇

猜你喜欢

热点阅读