Kotlin-构造函数(1)- 介绍

722 阅读4分钟
Kotlin与Java构造函数写法对比,以自定义View为例
  • 不同点:
  1. Kotlin以constructor命名构造函数,Java以类名命名构造函数;
  2. Kotlin构造可以没有方法体(花括号),Java必须得有(花括号);
  3. Kotlin init代码块可以做常规初始化处理,Java需要自定义类似init方法并主动调用;
  • 相同点:
  1. 两者super跟this含义一样;
//Kotlin写法
class MyViewKotlin : View {
    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    )

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

    init {
        //do something
    }
}

//Java写法
public class MyViewJava extends View {
    public MyViewJava(Context context) {
        super(context);
        init();
    }

    public MyViewJava(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MyViewJava(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public MyViewJava(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init() {
        //do something
    }
}
  • Kotlin的改进 一定有人觉得上述Java或Kotlin的写法过于繁琐,虽然AS可以自动生成,但是代码看起来就很冗余,接下来看下Kotlin是怎么玩的。
class MyViewKotlin : View {
    constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0,
        defStyleRes: Int = 0
    ) : super(
        context,
        attrs,
        defStyleAttr,
        defStyleRes
    )

    init {
        //do something
    }
}
       //调用一个参数的
        MyViewKotlin(this)
        //调用两个参数的
        MyViewKotlin(this, null)
        //调用三个参数的
        MyViewKotlin(this,null,0)
        //调用四个参数的
        MyViewKotlin(this,null,0,0)
  • 定义一个构造函数,给参数设置默认值,这样就相当于重载了多个构造函数可以满足不同场景。
Kotlin的默认构造函数、主构造函数、次构造函数
  • 默认构造函数:如果没有自定义任何构造函数,那么就会有一个默认无参的构造函数可以调用,这点跟Java一样;
  • 主构造函数:定义在类名后面的构造函数就是主构造函数,个数<=1;
  • 次构造函数:定义在类体内的构造函数都是次构造函数,个数 >=0;
//1 没有主构造函数,只有一个默认的无参构造函数
class Test1 {}

//2 有一个主构造函数,默认的无参构造函数无法使用,入参加上val、var修饰,那么属性就是全局的(类内有效),否则就是局部的(函数内有效),
class Test2 constructor(val name: String) {
}

//3只有一个主构造函数,如果构造函数没有任何修改符(例如private)或注解,那么constructor关键字可以省略,效果跟2一样
class Test3(val name: String) {
}

//4,有一个主构造函数和一个次构造函数
class Test4(val name: String) {
    var age: Int? = null
    constructor(name: String, age: Int) : this(name) {
        this.age = age
    }
}

//5,只有一个次构造函数
class Test5 {
    var name: String? = null
    var age: Int? = null

    constructor(name: String, age: Int) {
        name = name
        age = age
    }
}
Kotlin主、次构造函数的区别
  • 主构造函数定义在类名后,没有方法体,属性赋值会自动处理,使代码更简洁;
  • 次构造函数定义在类体内,有方法体,对于属性的赋值是在函数内,这跟Java类似;
Kotlin构造函数的特点
  • 如果定义了主构造函数,那么在init代码块中可以调用主构造函数的入参,因为init属于构造的一部分,而成员方法test就不行;
//这里的属性是局部变量,不是全局的
class Test7 constructor(name: String, age: Int) {

    init {
        //可以调用入参变量
        Log.i("Test7", "name=${name} age=${age}")
    }

    private fun test() {
        //无法调用入参变量
        Log.i("Test7", "name=${name} age=${age}")
    }
}
  • 次构造函数后面是调用this还是super,完全取决于该构造函数的功能,没有固定,但如果定义了主构造函数,那么次构造函数必须间接或者直接调用主构造函数;
open class Test8Parent {
    var name: String? = null
    constructor(name: String) {
        this.name = name
    }
}

//继承Test8Parent
class Test8 : Test8Parent {

    var age: Int? = 0
    var sex: Int? = 0

    //冒号后面是调用this还是super,完全取决于该构造函数的功能,没有固定
    constructor(name: String, age: Int) : this(name, 0, 0) {
        this.age = age
    }

    //冒号后面是调用this还是super,完全取决于该构造函数的功能,没有固定
    constructor(name: String, age: Int, sex: Int) : super(name) {
        this.sex = sex
    }
}
如果父类有主构造函数,子类也必须得有,否则提示"Supertype initialization is impossible without primary constructor"
open class Test9Parent(val name: String) {
}

//继承Test9Parent
class Test9(name: String, val age: Int, val sex: Int) : Test9Parent(name) {
}
总结
  • Kotlin,利用主构造函数以及设置参数默认值,可以重载多个构造函数,让代码更简洁;
  • Kotlin,定义主构造函数,用val、var修改入参,那么属性就是全局的,此构造函数无此能力;
  • Java调用MyViewKotlin的构造函数,因为带默认值的原因,需要加上@JvmOverloads注释;

以上分析有不对的地方,请指出,互相学习,谢谢哦!