Kotlin基础——类的构造函数的⼏种写法
本⽂⽬的
简单整理和罗列Kotlin语法中对类的构造函数的若⼲种写法,⽐官⽅⽂档更加⽣动具体的说明,并以Java作为对⽐参考,帮助想从Java 向Kotlin转型的初学者更加通俗易懂的了解Kotlin类的构造函数的语法。
构造函数
Kotlin语法规定了两种构造函数:主构造函数(primary constructor)和次构造函数(secondary constructors)。
下⾯引⽤官⽅⽂档的话:
“A class in Kotlin can have a primary constructor and one or more secondary constructors. ”
“在 Kotlin 中的⼀个类可以有⼀个主构造函数以及⼀个或多个次构造函数。”
主构造函数(primary constructor)
主构造函数紧跟在类名之后,⽤constructor修饰,有如下⼏种写法。
1. 标准写法
class Device constructor(deviceId: Int, deviceMac: String, deviceName: String) {
private val deviceId = deviceId
private val deviceMac = deviceMac
private var deviceName = deviceName
}
⼀个含有三个成员变量的Device类。此时要实例化⼀个Device对象,在构造⽅法中的这三个参数必须传递,不⽀持⽆参构造(使⽤⽆参构造实例化对象会报编译错误)。
2. 对标准写法的简化(省略constructor关键字)
class Device(deviceId: Int, deviceMac: String, deviceName: String) {
private val deviceId = deviceId
private val deviceMac = deviceMac
private var deviceName = deviceName
}
⼤多数情况下,没有其他修饰符修饰主构造函数的话,主构造函数的constructor关键字是可以省略的。
3. 对标准写法的进⼀步简化
class Device(private val deviceId: Int, private val deviceMac: String, private val deviceName: String) {
}
将成员变量直接写到了主构造函数的形参中,四⾏的代码压缩成⼀⾏就能搞定,看到Kotlin的简洁之处了吧,虽然对于初学者乍⼀看有点闷逼,但是这样可以⼤⼤提⾼开发效率。
如果初学者对上⾯三种⽅法看的迷糊的话,我把它翻译成Java,对⽐着看会更加易懂。
Java代码如下
public class Device {
private int deviceId;
private String deviceMac;
private String deviceName;
public Device(int deviceId, String deviceMac, String deviceName) {
this.deviceId = deviceId;
this.deviceMac = deviceMac;
this.deviceName = deviceName;
}
}构造函数可以被重载
讲到这⾥细⼼的读者可能发现上述的三种写法可能还满⾜不了⼀些其他需求,⽐如要对构造⽅法中传⼊的参数进⾏⼀些处理,下⾯举个在Adapter中经常遇到的Java代码的例⼦:
public class Adapter {
private LayoutInflater inflater;
private List<Object> data;
public Adapter(Context context, List<Object> data) {
this.inflater = LayoutInflater.from(context);
this.data = data;
}
}
这边并没有直接通过构造函数的参数对成员变量直接赋值,⽽是通过了LayoutInflater.from(context)⽅法的转换。然⽽Kotlin的主构造函数并没有代码块,如何⽀持以上操作呢?这⾥就引出了init关键字。
4. 使⽤init关键字初始化代码
class Adapter(context: Context?, data: List<Any>) {
private val inflater: LayoutInflater
private val data: List<Any> = data
init {
inflater = LayoutInflater.from(context)
}
}
注意:以上代码是有序执⾏的。另外,init代码块和Java中的static的代码块完全是两码事,前者是在对象的实例化时调⽤,后者是类加载时调⽤。
其实上⾯的写法并不是最简的,这⾥只是为了引出init⽽举个例⼦⽅法读者理解,下⾯再对这段代码进⼀步简化。
class Adapter(context: Context?, data: List<Any>) {
private val inflater: LayoutInflater = LayoutInflater.from(context)
private val data: List<Any> = data
}
对于存在修饰符的主构造函数,constructor关键字不能被省略,⽐如声明主构造函数为私有⽅法(默认是pubic的)就不能省略constructor,否则会报编译错误。
class Device private constructor(private val deviceId: Int, private val deviceMac: String, private val deviceName: String) { }
次构造函数(secondary constructors)
⾸先看看次构造函数是如何实现如上述例⼦仅有⼀个构造函数的情况
1. 单个构造函数下的次构造函数
class Device {
private val deviceId: Int
private val deviceMac: String
private var deviceName: String
constructor(deviceId: Int, deviceMac: String, deviceName: String){
this.deviceId = deviceId
this.deviceMac = deviceMac
this.deviceName = deviceName
}
}
这⾥的代码就有点类似Java的实现了,可见在类中仅有⼀个构造函数的情况下推荐使⽤更简介的主构造函数。
2. 多个次构造函数重载
class Device {
private val deviceId: Int
private val deviceMac: String
private lateinit var deviceName: String
constructor(deviceId: Int, deviceMac: String, deviceName: String) {
this.deviceId = deviceId
this.deviceMac = deviceMac
this.deviceName = deviceName
}
constructor(deviceId: Int, deviceMac: String){
this.deviceId = deviceId
this.deviceMac = deviceMac
}
}
或者
private val deviceId: Int
private val deviceMac: String
private lateinit var deviceName: String
constructor(deviceId: Int, deviceMac: String, deviceName: String) : this(deviceId, deviceMac){
this.deviceName = deviceName
}
constructor(deviceId: Int, deviceMac: String){
this.deviceId = deviceId
this.deviceMac = deviceMac
}
}
两种⽅法的区别就是后者通过⽤this关键字做了⼀个委托,本质是⼀样的。可见,存在多个次构造函数情况下,使⽤this关键字做委托不是必须的,这点要和下⾯介绍的第三种情况做区分。
3. 主构造函数和次构造函数共存
class Device(val deviceId: Int) {
private lateinit var deviceMac: String
private lateinit var deviceName: String
//this关键字直接委托给主构造函数
constructor(deviceId: Int, deviceMac: String) : this(deviceId){
this.deviceMac = deviceMac
}
//this关键字间接委托给主构造函数
constructor(deviceId: Int, deviceMac: String, deviceName: String) : this(deviceId, deviceMac) {
this.deviceName = deviceName
}
}
如果类中声明了主构造函数,再声明次构造函数的时候必须使⽤this关键字对主构造函数进⾏直接或间接的委托。注意:即使没有主构造函数这样的委托也会隐式发⽣的,⽽且这种委托发⽣在次构造函数的第⼀条语句,因此类中的init代码块会优先执⾏。如果看不懂前⾯这⼏句话,那就先看下⾯的实验。
//初始化块中的代码实际上会成为主构造函数的⼀部分
init {
println("first init")
}
//this关键字隐式委托给主构造函数
constructor(deviceId: Int, deviceMac: String){
println("second init")
}
//this关键字间接隐式委托给主构造函数
constructor(deviceId: Int, deviceMac: String, deviceName: String) : this(deviceId, deviceMac) {        println("third init")
}
companion object {
@JvmStatic
fun main(args: Array<String>) {
Device(123,"mac","name")
}
}
}
最终打印结果:
参考Kotlin官⽅⽂档:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。