开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第24天,点击查看活动详情
一、构造函数
1)、主构造函数的特点是没有函数体,直接跟在类名的后面即可,如果需要在主构造函数里面做逻辑,复写 init 函数即可
2)、主构造函数中声明成 val 或者 var 的参数将自动成为该类的字段,如果不加,那么该字段的作用域仅限定在主构造函数中
3)、构造函数是通过 constructor 关键字来定义的,当主构造函数无修饰符修饰的时候,可省略 constructor 关键字
4)、当一个类没有显示的定义主构造函数,但是定义了次构造函数时,那么被继承的类后面不需要加 ()
记住一个小技巧: Kotlin 中规定,需要显示的去声明调用的父类的构造函数
//情况1 定义一个主构造函数,无修饰符省略 constructor,定义一个 attr 属性
class ConstructorClass1 (var attr: String){
}
//情况2 定义一个主构造函数,使用修饰符修饰 constructor,定义一个 attr1 属性和一个 attr2 属性
class ConstructorClass2 @JvmOverloads constructor(var attr1: String,var attr2: Int){
}
//情况3 当一个类没有显示的定义主构造函数,但是定义了次构造函数时,那么被继承的类后面不需要加 ()
open class ParentClass(var attr1: String,var attr2: Int)
class ConstructorClass3 : ParentClass{
constructor(attr1: String,attr2: Int) : super(attr1,attr2){
}
}
//情况4 复写 init 代码块做一些初始化逻辑
class ConstructorClass4(var attr1: String){
init {
println("调用了 init 代码块1")
}
init {
println("调用了 init 代码块2")
}
constructor() : this("erdai666"){
println("调用了次构造函数")
}
}
fun main() {
ConstructorClass4()
}
//打印结果
调用了 init 代码块1
调用了 init 代码块2
调用了次构造函数
//情况5
open class ConstructorClass5(attr1: String){
val firstProperty = "First property: $attr1".also(::println)
init {
println("调用了ConstructorClass5 init 代码块1")
}
val secondProperty = "Second property: $attr1".also(::println)
init {
println("调用了ConstructorClass5 init 代码块2")
}
constructor() : this("erdai666"){
println("调用了 ConstructorClass5 次构造函数")
}
}
class SubConstructorClass5 : ConstructorClass5{
constructor() : super(){
println("调用了 SubConstructorClass5 次构造方法")
}
init {
println("调用了SubConstructorClass5 init 代码块1")
}
}
fun main() {
SubConstructorClass5()
}
//打印结果
First property: erdai666
调用了ConstructorClass5 init 代码块1
Second property: erdai666
调用了ConstructorClass5 init 代码块2
调用了 ConstructorClass5 次构造函数
调用了SubConstructorClass5 init 代码块1
调用了 SubConstructorClass5 次构造方法
根据上述打印我们可以得出 Kotlin 中构造函数调用的一些结论:
1、调用构造函数前的隐式三步骤:
1、调用父类的构造方法
2、初始化本类所有属性
3、初始化本类的 init 函数块
其中 2 和 3 是按照顺序从上往下执行的
2、继承结构的代码调用顺序:
1、初始化父类的属性和 init 函数块
2、初始化父类的构造方法
3、初始化本类的属性和 init 函数块
4、初始化本类的构造方法
二、SAM 接口
1、单抽象方法接口称为函数式接口或者 SAM(Single Abstract Method) 接口
2、SAM 转换就是将函数式接口的创建使用带接口类型前缀的 Lambda 表达式替换
fun interface IntPredicate {
fun accept(i: Int): Boolean
}
// 匿名内部类方式创建一个实例对象
val isEven = object : IntPredicate {
override fun accept(i: Int): Boolean {
return i % 2 == 0
}
}
// Lambda 表达式方式创建一个实例对象
val isEven = IntPredicate { it % 2 == 0 }
三、可见性修饰符
类比 Java,如下表:
| 修饰符 | Java | Kotlin |
|---|---|---|
| public | 所有类可见 | 所有类可见(默认) |
| private | 当前类可见 | 当前类可见 |
| protected | 当前类,子类,同一个包下的可见 | 当前类和子类可见 |
| default | 同一个包下的可见(默认) | 无 |
| internal | 无 | 同一个模块中的类可见 |
四、总结
本篇文章我们介绍了:
1、Kotlin 中的构造函数,并且通过 Log 打印得出了构造函数执行的一些结论
2、SAM 接口又称单抽象方法接口,这种接口我们可以使用带接口类型前缀的 Lambda 表达式进行接收
3、类比 Java 讲了 Kotlin 中的可见性修饰符
好了,本篇文章到这里就结束了,希望能给你带来帮助 🤝