1.主构造函数
package Kotlin.Stage4
//主构造函数,规范来说,都是增加_xxx的形式,临时的输入类型,不能直接用。需要接收下来,成为变量才能用。
class TestBase(_name:String,_sex:Char,_age:Int,_info:String){ //主构造函数
var name=_name
get() = field //get不允许私有化
private set(value) { //私有化的set在调用时 不能访问,无法set
field=value
}
val sex=_sex
get() = field
//set(value){} 由于是只读val的 因此无法使用set函数
var age=_age
get() = field +1
var info=_info
get() = "【$field】"
fun show(){
//println(_name) _name临时输入类型 不能直接用,需要接收才能用
println(name)
println(sex)
println(age)
println(info)
}
}
fun main() {
//创建对象
var p=TestBase(_name = "kotlin",_age = 20,_sex = '男',_info = "我是语言")
p.show()
}
执行结果
类似java中的this.nam=name
2.主构造函数里面定义属性
优化上述构造,一步到位
package Kotlin.Stage4
class TestBase1(var name:String,val sex:Char,var age:Int, var info:String){ //主构造函数
fun show(){
println(name)
println(sex)
println(age)
println(info)
}
}
fun main() {
//创建对象
var p=TestBase1(name = "kotlin",age = 20,sex = '男',info = "我是语言")
p.show()
}
执行结果
3.次构造函数
constructor()
package Kotlin.Stage4
class TestBase3(name:String){ //主构造
//次构造函数必须调用主构造,否在会报错。主构造统一管理,为了更好的初始化
//2个参数的次构造
constructor(name: String,sex:Char):this(name){
println("2个参数的次构造函数:name=$name,sex=$sex")
}
constructor(name: String,sex: Char,age:Int):this(name){
println("3个参数的次构造函数:name=$name,sex=$sex,age=$age")
}
constructor(name: String,sex: Char,age:Int,info:String):this(name){
println("3个参数的次构造函数:name=$name,sex=$sex,age=$age,info=$info")
}
}
fun main() {
//调用主构造
TestBase3("java")
//调用次构造
TestBase3("kotlin",'m')
TestBase3("kotlin",'m',25)
TestBase3("kotlin",'m',25,"我是语言")
}
执行结果
4.构造调用顺序
//第一步,生成主构造中的定义的变量
class Test60(name:String,_sex:Char,val age:Int){//主构造
//第二步,生成 var sex 在init{}前面写
var sex=_sex
init{
//第三步走init{}
println("主构造调用$name,$sex,$age")
}
constructor(name: String):this(name,'m',25){
//第五步 调用次构造
println("次构造调用")
}
//第四步
val dex="kotlin"
}
fun main() {
println()
Test59("java") //调用次构造
}
陷阱1:主构造中的变量赋值和init是同时的 看谁在前面
这么写会报错
class Test63(name : String){ //临时变量
init {
this.name=name
}
var name="java"
}
根据调用顺序,此时先执行init但是,name是临时变量,不能使用。
正确修改
class Test63(name : String){ //临时变量
var name="java"
init {
this.name=name
}
}
陷阱2:
class Test63{
val info:String
init {
getInfo()
info="java"
}
fun getInfo() {
println("info=${info[0]}")
}
}
fun main() {
Test63().getInfo()
}
执行结果
上述执行顺序为:Test63()主构造调用–>val info–>init(里面先调用了getInfo(),此时init还未初始化,因此空指针)
正确修改
陷阱3:
class Test63A(_info : String){
val concent=getInfoText()
val info=_info
fun getInfoText()=info
}
fun main() {
Test63A("java").concent.length
}
该调用顺序:主构造-concent-getInfoText(此时info还没接收_info) 所以空指针
最好是将接收的临时变量写到最上面
修改后:
5.构造函数默认参数
如果用户不传入参数,可以直接使用默认值
package Kotlin.Stage4
class TestBase4(name:String="java"){ //主构造
//次构造函数必须调用主构造,否在会报错。主构造统一管理,为了更好的初始化
//2个参数的次构造
constructor(name: String="kotlin",sex:Char='w'):this(name){
println("2个参数的次构造函数:name=$name,sex=$sex")
}
constructor(name: String="c",sex: Char='m',age:Int=25):this(name){
println("3个参数的次构造函数:name=$name,sex=$sex,age=$age")
}
constructor(name: String="c++",sex: Char='m',age:Int=35,info:String="我是语言"):this(name){
println("3个参数的次构造函数:name=$name,sex=$sex,age=$age,info=$info")
}
fun show(){
println("主构造函数调用结果")
}
}
fun main() {
//调用主构造
TestBase4("java")
//调用次构造
TestBase4("kotlin",'m')
TestBase4("kotlin",'m',25)
TestBase4("kotlin",'m',25,"我是语言")
//上述传入参数会覆盖默认参数
TestBase4().show() //此种情况下会优先调用主构造
}
执行结果
6.延迟初始化lateinit
1.关键字:lateinit var
2. lateinit val AAA
//不能使用val定义,因为不可修改,无法初始化
3.lateinit
作用就是先不赋值,等用到的时候在进行赋值,需要给定一个初始化的函数,供调用,kotlin中不给默认值会报错
4.在调用时必须先初始化 不然会报错
package Kotlin.Stage4
class Test61{
//lateinit val AAA //不能使用val定义,因为不可修改,无法初始化
lateinit var responseResult:String //先不赋值,等用到的时候在进行赋值
//模拟加载
fun loadRequest(){
responseResult="加载成功" //延时初始化
}
fun showResponseResult(){
//如果没有初始化,用到他时就会报错
if (responseResult==null){
println("显示结果")
}
println("显示结果$responseResult")
}
}
fun main() {
val p=Test61()
p.showResponseResult()
}
执行结果
上述报错原因是使用他之前没有调用初始化化的函数,被lateinit var的变量必须调用初始化才能用。
正确修改:
package Kotlin.Stage4
class Test61{
//lateinit val AAA //不能使用val定义,因为不可修改,无法初始化
lateinit var responseResult:String //先不赋值,等用到的时候在进行赋值
//模拟加载
fun loadRequest(){
responseResult="加载成功" //延时初始化
}
fun showResponseResult(){
//如果没有初始化,用到他时就会报错
if (responseResult==null){
println("显示结果")
}
println("显示结果$responseResult")
}
}
fun main() {
val p=Test61()
//使用前,先加载(用到他时在调用加载,属于懒加载)
p.loadRequest()
p.showResponseResult()
}
执行结果
5.使用::responseResult.isInitialized
的情况下,用到他时不会报错,会判断是否进行了初始化
class Test61{
//lateinit val AAA //不能使用val定义,因为不可修改,无法初始化
lateinit var responseResult:String //先不赋值,等用到的时候在进行赋值
//模拟加载
fun loadRequest(){
responseResult="加载成功" //延时初始化
}
fun showResponseResult(){
/* //如果没有初始化,用到他时就会报错
if (responseResult==null){
println("显示结果")
}
println("显示结果$responseResult")*/
if(::responseResult.isInitialized){
println("已经初始化")
}else{
println("未初始化")
}
}
}
fun main() {
val p=Test61()
//使用前,先加载(用到他时在调用加载,属于懒加载)
//p.loadRequest()
p.showResponseResult()
}
执行结果
7.惰性初始化
lateinit在加载时需要手动调用,然后在使用 by lazy直接可以使用
package Kotlin.Stage4
class Test62{
//lateinit val AAA //不能使用val定义,因为不可修改,无法初始化
val responseResult by lazy {loadRequest()}
//模拟加载
fun loadRequest():String{
println("正在加载中...")
return "加载成功"
}
fun showResponseResult(){
println("显示结果:$responseResult")
}
}
fun main() {
val p=Test62()
p.showResponseResult()
}
执行结果