Flutter 类和对象(一):类

在 Kotlin 中,类用关键字 class声明:

kotlin 复制代码
class Person { /*...*/ }

类的声明由:类名、类头信息(指定其类型参数、主构造函数以及其他一些内容)和由花括号包裹的类体。类头和类体都是可选的;如果没有类体,那么花括号可以省略:

kotlin 复制代码
class Empty

构造函数

在 Kotlin 中,一个类会有一个主构造函数和一个或者多个次要构造函数。主构造函数需要写在类头上,并且主构造函数需要写在类名后面,主构造函数还可以携带参数:

javascript 复制代码
class Person constructor(firstName: String) { /*...*/ }

如果主构造函数没有注解或者可见性标识符,那么constructor可以省略:

kotlin 复制代码
class Person(firstName: String) { /*...*/ }

主构造函数初始化类实例和类属性。类头不能包含可执行的代码。开发者可以使用初始化代码块,来在对象创建期间,执行一些代码。初始化代码块使用 init 声明,初始化代码块需要包裹在花括号之中。

During the initialization of an instance, the initializer blocks are executed in the same order as they appear in the class body, interleaved with the property initializers: 初始化代码块会按着自上而下的顺序执行,所以可能属性的赋值也会在代码块改变。

kotlin 复制代码
class InitOrderDemo(name: String) {
    val firstProperty = "First property: $name".also(::println)
    
    init {
        println("First initializer block that prints $name")
    }
    
    val secondProperty = "Second property: ${name.length}".also(::println)
    
    init {
        println("Second initializer block that prints ${name.length}")
    }
}
// 先给 firstProperty 赋值,
// 执行第一个init
// 再给secondProperty 赋值
// 执行第二个init

主构造函数的参数可以用在初始化代码块中。它们也可以用在代码体中的属性初始化中:

kotlin 复制代码
class Customer(name: String) {
    val customerKey = name.uppercase()
}

Kotlin 中有语法糖来实现声明和初始化属性:

kotlin 复制代码
class Person(val firstName: String, val lastName: String, var age: Int)

声明也可以包含默认的值:

kotlin 复制代码
class Person(val firstName: String, val lastName: String, var isEmployed: Boolean = true)

在声明类的属性时,可以使用末尾逗号:

kotlin 复制代码
class Person(
    val firstName: String,
    val lastName: String,
    var age: Int, // trailing comma
) { /*...*/ }

和常规属性类似,主函数中的属性可以是 var 或者 val

Plain constructor parameters (that are not properties) are accessible in: 未用var 或者 val修饰的构造参数在以下场景是可用的:

  • 类头
  • 类体中的已初始化属性
  • 初始化代码块

它们仅在初始化阶段有效,不成为类的成员,因此无法在类的方法中直接访问。

kotlin 复制代码
class RectangleWithParameters(width: Int, height: Int) {
    val perimeter = 2 * width + 2 * height

    init {
        println("Rectangle created with width = $width and height = $height")
    }
}

如果构造函数有注解或者可见性修饰符,那么 constructor 关键字是必须的,并且修饰符在 constructor 之前:

kotlin 复制代码
class Customer public @Inject constructor(name: String) { /*...*/ }

次构造函数

类也可以声明次要构造函数,次要构造函数使用 constructor 声明:

kotlin 复制代码
class Person(val pets: MutableList<Pet> = mutableListOf())

class Pet {
    constructor(owner: Person) {
        owner.pets.add(this) // adds this pet to the list of its owner's pets
    }
}

如果类本身有一个主构造函数,那么每个次要函数需要代理到主构造函数,要么直接调用,要么通过其他的次要函数调用。如果代理到一个类的其他构造函数,就可以使用 this 关键字:

kotlin 复制代码
class Person(val name: String) {
    val children: MutableList<Person> = mutableListOf()
    constructor(name: String, parent: Person) : this(name) {
        parent.children.add(this)
    }
}

初始化代码块实际上是主构造方法的一部分。代理到主构造函数的时机是访问次要构造函数第一句的时候,因此,所有的初始化代码块和初始化属性会在次要构造函数体之前调用。

即使类没有主构造函数,代理也会隐式发生,并且所有的初始化代码块依然会执行:

kotlin 复制代码
class Constructors {
    init {
        println("Init block")
    }

    constructor(i: Int) {
        println("Constructor $i")
    }
}
// first
// first block
// second
// second block
// Constructor 1

即使一个非抽象类没有声明构造函数(主要和次要),这个类也会生成一个无参的主要构造,并且这个构造是 public 的。

如果开发者不想要有一个 public 的构造,那么可以声明一个空的非默认可见性的主要构造:

kotlin 复制代码
class DontCreateMe private constructor() { /*...*/ }

创建类实例

开发者可以调用构造函数来实例化一个类,将实例化的对象来给变量赋值:

kotlin 复制代码
val invoice = Invoice()

val customer = Customer("Joe Smith")

类成员

类可以包含:

  • 构造方法和初始化代码块
  • 方法
  • 属性
  • 嵌套类和内部类
  • 对象声明

继承

类之间可以相互派生,形成继承层次结构。

抽象类

一个类可以被声明成抽象类,抽象类的部分或者全部成员可以是抽象的。一个抽象成员在类中是没有具体实现的。开发者不需要使用 open 来注解一个抽象类或者抽象方法。

kotlin 复制代码
abstract class Polygon {
    abstract fun draw()
}

class Rectangle : Polygon() {
    override fun draw() {
        // draw the rectangle
    }
}

开发者可以使用抽象来重写一个非抽象的open成员。

kotlin 复制代码
open class Polygon {
    open fun draw() {
        // some default polygon drawing method
    }
}

abstract class WildShape : Polygon() {
    // Classes that inherit WildShape need to provide their own
    // draw method instead of using the default on Polygon
    abstract override fun draw()
}

伴生对象

开发者可以在类内容声明一个伴生对象,这样就可以在不创建对象的情况下,使用伴生对象访问类的成员。

原文链接

相关推荐
补三补四7 小时前
贝叶斯向量自回归模型 (BVAR)
android·算法·数据挖掘·数据分析·回归
future_studio9 小时前
如何用 Android 平台开发第一个 Kotlin 小程序
android·gitee
tangweiguo030519879 小时前
Kotlin 协程异步任务工具类:高效处理异步操作与超时控制
android·kotlin
泽02029 小时前
Linux自动化构建工具-make/Makefile
android·linux·自动化
Just_Paranoid10 小时前
【Audio】切换至静音或振动模式时媒体音自动置 0
android·audio·audiomanager·audioservice
用户20187928316710 小时前
View设置setSoundEffectsEnabled为false后点击时还发出反馈音之谜
android
爱学习的小道长10 小时前
使用 Dify 和 LangBot 搭建飞书通信机器人
android·java·飞书
胖虎110 小时前
Android入门到实战(六):Android主流图片加载框架
android·glide·android图片加载
Kapaseker10 小时前
Compose 图片加载新姿势 — Coil 精通
android·kotlin