Kotlin-构造函数

2021-03-01  本文已影响0人  杨0612
1.Kotlin与Java构造函数常规写法对比,以自定义View为例
不同点:

1.1 Kotlin以constructor命名构造函数,Java以类名命名构造函数;
1.2 Kotlin构造可以没有方法体(花括号),Java必须得有(花括号);
1.3 Kotlin init代码块可以做常规初始化处理,Java需要自定义类似init方法并主动调用;

相同点:
1.4 两者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
    }
}
2.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)
3.Kotlin的默认构造函数、主构造函数、次构造函数

默认构造函数:如果没有自定义任何构造函数,那么就会有一个默认无参的构造函数可以调用,这点跟Java一样;
主构造函数:定义在类名后面的构造函数就是主构造函数,个数<=1;
次构造函数:定义在类体内的构造函数都是次构造函数,个数 >=0;

//案例1,没有主构造函数,只有一个默认的无参构造函数
class Test1 {}

//案例2,有一个主构造函数,默认的无参构造函数无法使用
class Test2 constructor(name: String) {
    var name: String = name
}

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

//案例4,有一个主构造函数和一个次构造函数
class Test4(name: String) {
    var nameT: String = name
    var ageT: Int? = null

    constructor(name: String, age: Int) : this(name) {
        ageT = age
    }
}

//案例5,只有一个次构造函数
class Test5 {
    var nameT: String? = null
    var ageT: Int? = null

    constructor(name: String, age: Int) {
        nameT = name
        ageT = age
    }
}
4.Kotlin主、次构造函数的区别

主构造函数定义在类名后,没有方法体,对于属性的赋值直接跟在属性定义后面,使代码更简洁;
次构造函数定义在类体内,有方法体,对于属性的赋值是在函数内,这跟Java类似;

class Test6 constructor(name: String, age: Int) {
    //主构造函数的属性赋值,也可以通过init代码块赋值
    var nameT: String = name
    var ageT: Int? = age

    var sexT: Int? = null

    constructor(name: String, age: Int, sex: Int) : this(name, age) {
        //次构造函数的赋值
        sexT = sex
    }
}
5.Kotlin构造函数的特点
5.1如果定义了主构造函数,那么在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}")
    }
}
5.2 次构造函数后面是调用this还是super,完全取决于该构造函数的功能,没有固定,但如果定义了主构造函数,那么次构造函数必须间接或者直接调用主构造函数;
open class Test8Parent {
    var nameT: String? = null
    constructor(name: String) {
        nameT = name
    }
}

//继承Test8Parent
class Test8 : Test8Parent {

    var ageT: Int? = 0
    var sexT: Int? = 0

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

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

//继承Test9Parent
class Test9(name: String, age: Int, sex: Int) : Test9Parent(name) {
    var ageT: Int? = age
    var sexT: Int? = sex
}
5.3 如果定义了主构造函数,可以把入参当作属性,省去定义;
class Test10 constructor(name: String, age: Int) {
    //常规定义属性的办法
    var nameT: String? = name
    var ageT: Int? = age
    private fun test() {
        Log.i("Test7", "name=${nameT} age=${ageT}")
    }
}

//把入参当作属性
class Test11 constructor(var nameT: String, var ageT: Int) {
    private fun test() {
        Log.i("Test7", "name=${nameT} age=${ageT}")
    }
}
6.总结
6.1Kotlin,利用主构造函数以及设置默认值,可以让构造函数更简洁;
6.2Kotlin,定义主构造函数,可以在定义属性的时候就赋值;
6.3Kotlin,定义主构造函数,把入参当作属性,让代码更简洁;

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

上一篇下一篇

猜你喜欢

热点阅读