* 在Java中可以声明一个或多个构造方法。Kotlin也是一样的,只是做了一点修改:
* 区分了 主构造方法(通常是主要而简洁的初始化类的方法,并且声明在类外部声明)和 从构造方法(在类的内部声明)
* 同样也允许在初始化语句块中添加额外的初始化逻辑。
/** * 这里被括号围起来的语句块就叫做“主构造方法”,它的目的有两个: * 表明构造方法的参数,以及定义使用这些参数的初始化的属性 */ class User(val username: String)
下面的类声明是上面类声明的完成代码
class User_ constructor(_nickName: String) { val nickName: String init { println("init 1") nickName = _nickName } init { println("init 2") }
* 上面的例子中出现了两个关键字:constructor 、 init
* constructor用来开始一个主构造方法的声明。init关键字用来引入一个初始化语句,“初始化语句块”包含了再类被创建的时候所执行的代码,并会与主构造方法一起使用。
* 因为主构造方法受语法限制,不能包含初始化代码,这就是为什么要使用初始化语句的原因。而且,可以再一个类中声明多个初始化语句块
* 在上面的例子中不需要把初始化代码放到初始化语句块中,因为它可以与nickName属性的声明结合。
* 如果主构造方法没有注解或者可见性修饰符,同样可以去掉constructor修饰符,如下面的声明
class User0(_nickName: String) { val nickName = _nickName }
* 在上面的两个列子中,使用val 声明了属性。
* 如果属性用相应的构造方法参数来初始化代码可以通过把val关键字加在参数前的方式来进行简化,这样就能替换掉类中的属性定义,如下
class User1(val name: String) //val 意味着响应的属性会用构造方法的参数来初始化
* 可以像普通函数一样,为构造方法参数声明一个默认值
* 如果所有的构造方法参数都有默认值,编译器会生成一个额外的不带参数的构造方法来使用所有的默认值,这可以让Kotlin使用库的时候变得简单,因为可以使用无参的构造方法来实例化。
class User2(val name: String, val isSubscribed: Boolean = false)
接下来展示带有继承的构造方法,首先给出个父类
open class Student(val name: String)
* 如果你的类具有一个父类,主构造方法同样要初始化父类,可以通过在基类列表的父类引用中提供 父类构造方法参数 的方式来做到这一点
class TwitterStudent(nick: String) : Student(nick)
* 如果没有给一个类声明任何构造方法,将会生成一个不带参数的不做任何事的默认构造函数
open class Animal
* 自动生成的默认的无参的构造函数就是为什么在继承一个类的时候加括号的原因,注意与接口实现的区别
* 接口没有构造方法,所以在你实现一个接口的时候不需要在父类型列表中它的名称后面再加上括号
class Bird : Animal() {}
* 如果想让要确保一个类不被其他代码实例化,就必须把构造方法标为private的
* Kotlin中的单例工具类会少甚多,因为顶层函数可以作为静态实用工具
class Secretice private constructor() {}
* Kotlin中不主张声明多个重载的构造函数,取而代之的应该是直接标记默认参数。
* 但是,Kotlin 也是支持多个构造方法的,如下
* View1没有主构造方法,但是它声明了两个从构造方法,从 构造方法也用constructor 引出,也一样可以声明多个从构造方法
open class View1 { constructor(ctx: String) { //.. } constructor(ctx: String, attr: Int) { //.. } }
* 如果要扩展上面的View1,同样可以声明多个从构造方法
class EditText : View1 { /** * 在构造方法后面使用 :this 来调用本类的构造方法 */ constructor(ctx: String) : this(ctx, 1) { } /** * 在构造方法后面使用 :super 来调用父构造方法 */ constructor(ctx: String, attr: Int) : super(ctx, attr) { } constructor(ctx: String, attr: Int, args: Array<String>) : super(ctx) { } }
* 如果有主构造方法,就可以直接在声明子类的时候初始化父类的方法,
* 像EditText,如果没有主构造方法,那么每个从构造方法必须初始化基类,或者委托给另一个这样做了的从构造方法。
* 每个构造方法必须以一个朝外的箭头开始并且结结束于任意一个基类构造方法
class TextView(ctx: String) : View1(ctx) {}