Android学习Kotlin之四、定义类-初始化-继承
Kotlin标准库函数
Kotlin定义一个类很简单,和java一样声明需要的变量属性,在kotlin中省略了get()和set()函数默认支持get()和set(),并且可以自定义get()和set()函数;初始化类时顺序很重要,如果代码顺序写错了会很容易报错;类通过open修饰可被继承,和java不同的是kotlin的函数也需要通过open修饰后子类才可以继承。
其它Kotlin文章
Android学习Kotlin之一、常量-条件-函数-高阶函数
Android学习Kotlin之二、Null安全 -字符串操作- 类型转换
Android学习Kotlin之三、标准库函数-集合List-Set-Map
Android学习Kotlin之四、定义类-初始化-继承
Android学习Kotlin之五、对象-接口-抽象类
Android学习Kotlin之六、泛型-扩展函数
本编文章会讲到的知识点
- 定义类
- field
- 计算属性
- 初始化类
- 主构造函数使用临时变量
- 主构造函数中直接定义属性变量
- 次构造函数
- 初始化块
- 初始化顺序
- 延迟初始化lateinit
- 惰性初始化lazy
- 继承
- open继承
- 类型检测
- as智能转换
- Any类
定义类
field
针对你定义的每一个属性,Kotlin都会产生-个field、一个getter、 以及一个setter, field用来存储属性数据,你不能直接定义field, Kotlin会封装 field,保护它里面的数据,只暴露给getter和setter使用。属性的getter方法决定你如何读取属性值,每个属性都有getter方法,setter方 法决定你如何给属性赋值,所以只有可变属性才会有setter方法,尽管Kotlin会自动提供默认的getter和setter方法,但在需要控制如何读写属性数据时,你也可以自定义他们。
- 定义一个Student类,里面定义变量,kotlin默认提供的就有get、set方法,也可以自定义get、set方法。
class Student {
var name = "小明"
get() = field.capitalize()
set(value) {
field = value.trim()//自定义set去除空格
}
var age = -12
//自定义get和set函数,实际根据自己需求来自定义get和set
get() = field.absoluteValue//自定义取绝对值
set(value) {
field = value.absoluteValue
}
var adder:String? = "杭州"
}
- 创建Student对象,调用属性的get、set方法使用
var student = Student()
student.name = " 老王 "//估计前后写空格
println(student.name)//打印老王 没有空格
println(student.age)
student.age = -6
println(student.age)//打印 是正6 因为自定义get中取绝对值了
fun getAdder(){
//如果adder不为空才会打印
student?.adder?.also {
println("地址=${it}")
}
}
getAdder()
计算属性
计算属性是通过- -个覆盖的get或set运算符来定义,这时field就不需要 了。
var value: Int? = null
get() = (1..10).random()//自定义返回值get不使用field
var student = Student()
println(student.value)//返回1-10的随机数
初始化类
主构造函数使用临时变量
我们在Teacher类的定义头中定义一个主构造函数,使用临时变量为Teacher的各个属性提供初始值,在Kotlin中, 为便于识别,临时变量(包括仅引用一-次的参数),通常都会以下划线开头的名字命名。
class Teacher(
_name: String,
_age: Int,
) {
var name = _name
var age = _age
override fun toString(): String {
return "Teacher(name='$name', age=$age)"
}
}
var teacher = Teacher("何炅", 50)
println(teacher.name)//何炅
println(teacher.toString())//Teacher(name='何炅', age=50)
打印.png
主构造函数中直接定义属性变量
Kotlin允许你不使用临时变量赋值,而是直接用一个定义同时指定参数和类属性,通常,我们更喜欢用这种方式定义类属性,因为他会减少重复代码。定义构造函数时,可以给构造函数参数指定默认值,如果用户调用时不提供值参,就使用这个默认值。
class Teacher2(
var name: String,
var age: Int = 10//可以设置默认值
) {
override fun toString(): String {
return "Teacher2(name='$name', age=$age)"
}
}
var teacher2 = Teacher2("黄磊", 52)
println(teacher2.name)//黄磊
println(teacher2.toString())//Teacher2(name='黄磊', age=52)
次构造函数
有主就有次,对应主构造函数的是次构造函数,我们可以定义多个次构造函数来配置不同的参数组合,通过this指向把值传递给了主构造函数。可以在次构造函数中进行初始化代码逻辑,比如修改参数值。
class Teacher3(
var name: String,
var age: Int,
) {
//次构造函数 通过this指向把值传递给了主构造函数
constructor(name:String):this(name,0){
//这里可以进行初始化代码逻辑,给age赋值
this.age = 18
}
override fun toString(): String {
return "Teacher3(name='$name', age=$age)"
}
}
val teacher3 = Teacher3("黄晓明")//调用的是次构造函数 没有传age值
println(teacher3.toString())//Teacher3(name='黄晓明', age=18)
初始化块
初始化块可以设置变量或值,以及执行有效性检查, 如检查传给某构造函数的值是否有效,初始化块代码会在构造类实例时执行。
class Teacher4(
var name: String,
var age: Int,
) {
init {
println("${name} "+if (age>18) "满18" else "未满18")
age = if (age > 18) 1 else 0 //判断age的值 然后修改age的值
}
override fun toString(): String {
return "Teacher4(name='$name', age=$age)"
}
}
var teacher4 = Teacher4("马云",20)
println(teacher4.toString())//Teacher4(name='马云', age=1)
初始化顺序
1.主构造函数里声明的属性
2.类级别的属性赋值
3.init初始化块里的属性赋值和函数调用
4.次构造函数里的属性赋值和函数调用
class Teacher5(
var name: String,
var age: Int,
) {
var hight: Int = 175
init {
println("初始化块 ${name} " + if (age > 18) "满18" else "未满18")
}
constructor(name: String) : this(name, 10) {
hight = 180
println("这里是次构造函数")
}
override fun toString(): String {
return "Teacher5(name='$name', age=$age, hight=$hight)"
}
}
var teacher5 = Teacher5("小马云")
println(teacher5.toString())
初始化顺序
延迟初始化lateinit
- 只能用在var变量上;
- 使用lateinit关键字相当于做了一一个约定:在用它之前负责初始化;
- 只要无法确认lateinit变量是否完成初始化,可以执行isInitialized检查;
只能用在var变量上;该修饰只能用于类体中(不是在主构造函数中)声明的var属性,注意是var(可变属性)并且仅当该属性没有自定义getter或setter时,该属性必须是非空类型,并且不能是原生类型。
class Teacher6 {
lateinit var name: String
init {
name = "中国惊奇先生"
}
fun getName() {
if (::name.isInitialized) println(name) else println("name为空")
}
}
val teacher6 = Teacher6()
teacher6.getName()
惰性初始化lazy
- 只能用在val变量上
延迟初始化并不是推后初始化的唯一方式, 你也可以暂时不初始化某个变量,直到首次使用它,这个叫作惰性初始化。
class Teacher7 {
val name: String by lazy {
println("马上赋值")
"镇魂街"
}
fun getName(){
println(name)
}
}
val teacher7 = Teacher7()
//第一次调用打印 “马上赋值” “镇魂街”
teacher7.getName()
//第二次调用只打印值,不会执行lazy{}过程
teacher7.getName()
继承
open继承
默认都是封闭的,要让某个类开放继承,必须使用open关键字修饰它。父类的函数也要以open关键字修饰,子类才能覆盖它。
open class Animal(var name: String) {
//父类的函数也要以open关键字修饰,子类才能覆盖它。
open fun getName() {
println("this is ${name} ")
}
}
class Cat : Animal("小狗") {
override fun getName() {
// super.getName()
println("this2 is ${name} ")
}
}
val cat = Cat()
println(cat.name)//小狗
cat.getName()//this2 is 小狗
类型检测
Kotlin的is运算符是个不错的工具,可以用来检查某个对象的类型。
val cat2 = Cat()
println(cat2 is Cat)//true
println(cat2 is Animal)//true
as智能转换
as操作符声明,这是一个类型转换。/为了避免抛出异常,可以使用安全转换操作符 as?,它可以在失败时返回 null。
println(cat2 as Animal)
var c = cat as Animal
// var c1 = cat2 as Animal2//报错 java.lang.ClassCastException
var c1 = cat2 as? Animal2//为了避免抛出异常,可以使用安全转换操作符 as?,它可以在失败时返回 null
println(c1)
c?.getName()//this2 is 小狗
Any类
无须在代码里显示指定,每一-个类都会继承一个共同的叫作Any的超类。
val cat = Cat()
println(cat is Any)// true
println(cat as Any)// com.example.kotlinjetpack.kotlin.Cat@66d3c617