《Kotlin核心编程》 ——3.1.3 主从构造方法

举报
华章计算机 发表于 2020/02/21 22:32:35 2020/02/21
【摘要】 本节书摘来自华章计算机《Kotlin核心编程》 —— 书中第3章,第3.1.3节,作者是水滴技术团队 。

3.1.3 主从构造方法

我们似乎遗漏了另一些常见的情况。有些时候,我们可能需要从一个特殊的数据中来获取构造类的参数值,这时候如果可以定义一个额外的构造方法,接收一个自定义的参数会显得特别方便。

同样以鸟为例,先把之前的Bird类简化为:

class Bird(age: Int) {

    val age: Int

 

    init {

        this.age = age

    }

}

假设当前我们知道鸟的生日,希望可以通过生日来得到鸟的年龄,然后创建一个Bird类对象。如何实现?

第1种方案是在别处定义一个工厂方法,如:

import org.joda.time.DateTime

 

fun Bird(birth: DateTime) = Bird(getAgeByBirth(birth))

应该在哪里声明这个工厂方法呢?这种方式的缺点在于,Bird方法与Bird类在代码层面的分离显得不够直观。

一种改进方案是在Bird类的伴生对象中定义Bird方法。我们会在后续的节中介绍这种技术。

显然我们可以像Java那样新增一个构造方法来解决这个问题。其实Kotlin也支持多构造方法的语法,然而与Java的区别在于,它在多构造方法之间建立了“主从”的关系。现在我们来用Kotlin中的多构造方法实现这个例子:

import org.joda.time.DateTime

 

class Bird(age: Int) {

    val age: Int

 

    init {

        this.age = age

    }

 

    constructor(birth: DateTime) : this(getAgeByBirth(birth)) {

        ...

    }

}

来看看这个新的构造方法是如何运作的:

通过constructor方法定义了一个新的构造方法,它被称为从构造方法。相应地,我们熟悉的在类外部定义的构造方法被称为主构造方法。每个类可最多存在一个主构造方法和多个从构造方法,如果主构造方法存在注解或可见性修饰符,也必须像从构造方法一样加上constructor关键字,如:

internal public Bird @inject constructor(age: Int) { ... }

每个从构造方法由两部分组成。一部分是对其他构造方法的委托,另一部分是由花括号包裹的代码块。执行顺序上会先执行委托的方法,然后执行自身代码块的逻辑。

通过this关键字来调用要委托的构造方法。如果一个类存在主构造方法,那么每个从构造方法都要直接或间接地委托给它。比如,可以把从构造方法A委托给从构造方法B,再将从构造方法B委托给主构造方法。举个例子:

import org.joda.time.DateTime import org.joda.time.Years

class Bird(age: Int) { val age: Int init { this.age = age } constructor(timestamp: Long): this(DateTime(timestamp)) //构造函数A constructor(birth: DateTime): this(getAgeByBirth(birth)) //构造函数B }

fun getAgeByBirth(birth: DateTime): Int { return Years.yearsBetween(birth, DateTime.now()).years }

现在你应该对Kotlin中的主从构造方法有了一定的了解了。其实,从构造方法的设计除了解决我们以上的场景之外,还有一个很大的作用就是可以对某些Java的类库进行更好地扩展,因为我们经常要基于第三方Java库中的类,扩展自定义的构造方法。如果你从事过Android开发肯定了解,典型的例子就是定制业务中特殊的View类。比如以下的代码:

class KotlinView : View {

    constructor(context: Context) : this(context, null)

    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) :

super(context, attrs, defStyleAttr) {

        ...

    }

}

可以看出,利用从构造方法,我们就能使用不同参数来初始化第三方类库中的类了。


【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。