Kotlin与Java构造函数写法对比,以自定义View为例
- 不同点:
- Kotlin以constructor命名构造函数,Java以类名命名构造函数;
- Kotlin构造可以没有方法体(花括号),Java必须得有(花括号);
- Kotlin init代码块可以做常规初始化处理,Java需要自定义类似init方法并主动调用;
- 相同点:
- 两者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注释;
以上分析有不对的地方,请指出,互相学习,谢谢哦!