Kotlin学习笔记五-kotlin 类

kotlin类

属性

1-field
对于kotlin,类的每一个属性都会产生一getter,一个setter,一个filed。filed不能定义,只是暴露给get和set使用。需要控制读写数据时,可以自定义getter和setter,来达到需求。对于private,反编译成java不会产生setter,getter。
get(),set()直接紧跟定义的变量
eg
var a=“jack”
get()=filed.capesclip()
set(value){
field=…}

get set也可以设为private 不暴露给外面

注意 ,val没有set。同时二者也受private影响,所以针对的是public。
一般情况下,是不需要我们自定义这两个方法的,只有特殊的运用场景会需要自定义变量的set和get。我们只用知道变量有field属性即可。

其实也可以和传统java编程一样,写一些自定义的setAge(),getAge()方法来替代与kotlin自己封装的set(),get(),个人感觉优先采用kotlin的写法(针对公有变量,还是得传统写法),这样会让类的使用更加简洁,至少代码层面减少了方法的定义
传统写法:【没有涉及field属性】

//一般java里,对于私有变量,或者值需要进一步处理再暴露给外部,会这么写
fun setAge(age: Int) {
this.age = age
}

fun getAge(): Int {
    return this.age
}

2-计算属性
如果返回结果与原来值无关,就不用filed.通过一个覆盖的get或者set来定义变量。
与原来值有关:
val age
get()=field.absulutevalue()
与原来值无关:
eg val num
get()={1…6}.suffered.first()//不需要field
可以通过这样的方式,产生一个随机数变量
总而言之,就是类里面的变量,我们可以为它自定义get和set方法(可以选择是否暴露给外面),而且不一定要用到field属性。

3-防范竞态条件
果一个属性可空又可变 , 那么引用之前要保证它非空,那么就使用also ,其实用let应该也一样,看具体场景,保证代码优雅就行。主要是知道竞态条件-可空又可变,引用保证非空。其实具体项目中一直用到
eg var str:stribg?
str?.also{
引用干的事
print(str)
}

类的构造函数

主构造函数

(1)编码规范 对于只使用一次的变量 (临时变量)以下划线开头,例如柱构造函数里的参数,但是大多情况下,是直接在主构造函数里定义属性,例如

//kotlin,主构造函数就是直接跟在类名后的
class a(var a:string,var b:strng){
var c:String

}
注意:没必要把所有属性都写在构造函数里,按需
对于临时变量
fun setAb(_a:string,_b:string){
c=_a+_b
}

次构造函数

当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(包括间接调用)。
eg


class A(val  a:String,val b:String){
val c:Int
}
//子类B有主构造函数
//就必须super A类的主构造方法,这里直接在子类主构造方法后就调用
class B(val  a:String,val b:String,val d:String) :A(a,b)//调用父类构造方法
{
//次构造方法,这里不定义变量,需要调用主构造方法
constor( _a:String, _b:String, _d:String,_c:String):this(_a,_b,_d){
this.c=_c

}
}

如果B类没有主构造方法,那么定义时,只用在次构造里super调用A类的构造方法即可,不用在子类构造方法后super调用父类构造方法

//子类B无主构造方法
class B :A
//不用super调用父类构造方法
{
//次构造方法,这里只调用父类的构造方法,因为没有主构造函数
constor( _a:String, _b:String, _d:String,_c:String):super(_a,_b){
this.c=_c

}
}

其实子类有无主构造方法,只是涉及到我们super调用父类构造方法的时机。
如果父类存在有参数的构造方法(这代表父类没有无参数的构造方法了),那么子类是一定super父类的构造方法的。

https://blog.csdn.net/qq_35178391/article/details/106786166

初始化块

JAVA static 静态代码快 在类加载的时候执行
kotlin
init{
}在构造实例对象的时候执行
可以做一些赋值 检查工作 可能检查工作多一点 因为赋值 在构造函数就可以完成

初始化顺序

主构造函数 -》类级别属性赋值 -》初始化块 -》次构造函数

变量的初始化

kotlin是空安全的,对于非空变量,一般要求立即赋值(初始化)。如果变量非空,而且定义变量时没有初始化,那么使用变量时会抛异常。

例如

//没有?,代表变量非空
val a :String

那么如何地方使用a变量(即时你已经做了赋值),编译器都会抛异常

(1)延时初始化(饿汉
lateinit var str

lateinit val a :String
这样就不会报错

lateinit的意义是,告诉编译器,我们自己检查变量是否初始化,你不用报错。
这个要慎用,如果使用lateinit,最好使用变量时,做是否初始化的判断
例如 str.isInitialized函数帮助检查

https://www.cnblogs.com/alan6y/p/13622571.html

(2)惰性初始化(懒汉
val config by lazy{
loadconfig()
}
事先写好初始化方法 用到的时候初始化
viewmodel 初始化就是这样的 工厂方法

初始化陷阱

初始化陷阱 1
使用初始化块时,顺序非常重要
块中使用的属性 必须保证初始化已经完成
例如 intt{
val b=a-2
}
val a=3
这样写 会编译报错 a没有初始化
虽然我们理解的初始化顺序 a=3在init之前
但是 kotlin a=3 必须在init块之前 这和java不一样

初始化陷阱二
其实就是注意初始化顺序
eg
val a:int
init{
print(a)//引用到a的方法
a=4
}
这样编译不报错(因为不是在方法里引用a), 但是运行报错

初始化陷阱三
kotlin 类里面 属性是按顺序初始化的
player(_name){
val personname=name
val name=_name
}

player(“点解点解”)
这样 personname是空的
java是不受顺序影响的 这就是编译型语言


版权声明:本文为qq_46577594原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。