上次介绍了kotlin中的集合List、Set、Map的操作,接下来介绍kotlin中如何定义类、初始化、继承
一、类的定义
1.field
对于每个属性,kotlin会自动生成一个的field:代表属性的值,一个getter方法,一个setter方法。我们操作属性时,实际调用的是get和set方法,因为kotlin变量的不可空性,对于非空变量,我们在赋值时,系统要对赋值的值进行是否为null判断
代码语言:javascript复制class Human {
var name: String? = null
var age: Int = 5
}
我们可以自定义get和set方法,需要写在对应变量的下面
代码语言:javascript复制class Human {
var name: String? = null
get() {
//如果不是null,返回首字母大写,否则返回"Null"字符串
return field?.capitalize() ?: "Null"
}
set(value) {
//value为null,赋值成"Null"字符串,否则赋值成小写字符串
field = value?.toLowerCase() ?: "Null"
}
var age: Int = 5
set(value) {
//负数抛出异常
require(value > 0) { "不能为负数" }
field = value
}
}
2.计算属性
get和set也可以直接赋值成表达式
代码语言:javascript复制class Human2 {
var name: String? = null
val age
//年龄为随机数
get() = (1..100).shuffled().first()
}
3.防范竞态条件
和可空变量一样,如果属性可空,那么使用它的时候必须保证它非空
代码语言:javascript复制class Human2 {
var name: String? = null
val age
//年龄为随机数
get() = (1..100).shuffled().first()
fun capitalizeName() {
name = name?.capitalize()
}
}
二、初始化
和Java实例化有很多不同,kotlin的初始化更加灵活
1.主构造函数
在类的定义头中定义主构造函数,使用临时变量为属性赋值
代码语言:javascript复制class Human3(
_age: Int,
_name: String
) {
var name: String? = _name
var age = _age
}
2.在主构造函数定义属性
kotlin允许直接用一个定义,同时指定类属性和参数
代码语言:javascript复制class Human4(
_name: String,
var age: Int
) {
var name: String? = _name
}
3.次构造函数
使用constructor来创建次构造函数
代码语言:javascript复制class Human5(
_name: String,
var age: Int
) {
var name: String? = _name
constructor(_name: String) : this(_name, age = 0) {
this.name = _name.toLowerCase()
}
}
4.默认参数值
定义构造函数时,可以指定参数值,如果用户不提供,则使用默认值
代码语言:javascript复制class Human6(
_name: String,
var age: Int = 10
) {
var name: String? = _name
}
代码语言:javascript复制fun main() {
val h4 = Human6(_name = "张三")
println(h4.name)
println(h4.age)
}
结果:
张三
10
5.初始化块
初始化块,相当于默认提供了一个初始化方法,可以设置变量或值,以及执行有效性检查,初始化块在实例化时执行
代码语言:javascript复制class Human7(
_name: String,
var age: Int = 10
) {
var name: String? = _name
init {
name = name?.capitalize()
}
}
6.初始化顺序
kotlin代码和反编译成Java代码对比:
7.延迟初始化
使用关键字lateinit来表示使用时,才初始化参数,构造时并不会初始化占用内存
可以执行isInitialized检查是否初始化
代码语言:javascript复制class Human8(
_name: String,
var age: Int = 10
) {
var name: String? = _name
lateinit var gender: String
fun isGenderInit(): Boolean {
return ::gender.isInitialized
}
}
代码语言:javascript复制fun main() {
val h8 = Human8(_name = "zhangsan")
println(h8.isGenderInit())
}
结果:
false
8.惰性初始化
惰性初始化也可以实现延迟初始化
代码语言:javascript复制class Human9(
_name: String,
var age: Int = 10
) {
var name: String? = _name
val gender by lazy { genderInit() }
private fun genderInit(): String {
println("init ${System.currentTimeMillis()}")
return "0"
}
}
测试:
代码语言:javascript复制fun main() {
println("start ${System.currentTimeMillis()}")
val h9 = Human9(_name = "zhangsan")
Thread.sleep(3000)
println(h9.gender)
println("end ${System.currentTimeMillis()}")
}
结果:
start 1629701476608
init 1629701479710
0
end 1629701479710
三、继承
1.类继承
kotlin默认每个类都是封闭的,如果要开放继承,使用关键字"open"
代码语言:javascript复制open class Human(
var name: String,
var age: Int
) {
}
class female(
_name: String,
_age: Int,
var height: Int = 0
) : Human(_name, _age) {
}
2.函数重载
父类函数也需要"open"关键字修饰才能重载,并且重载的函数要加上"override"关键字
代码语言:javascript复制open class Human(
var name: String,
var age: Int
) {
open fun work() = "Human working"
}
class Female(
_name: String,
_age: Int,
var height: Int = 0
) : Human(_name, _age) {
override fun work() = "female working"
}
fun main() {
val h: Human = Female("tom", 18)
println(h.work())
}
结果:
female working
3.类型检测
Java中使用:”instanceof“ ,kotlin中使用:”is“
代码语言:javascript复制fun main() {
val h: Human = Female("tom", 18)
println(h.work())
println(h is Human)
}
4.类型转换
Java强转类型使用(类名),kotlin使用"as"关键字
代码语言:javascript复制open class Human(
var name: String,
var age: Int
) {
open fun work() = "Human working"
}
class Female(
_name: String,
_age: Int,
var height: Int = 0
) : Human(_name, _age) {
override fun work() = "female working"
fun sleep() = "sleep"
}
fun main() {
val h: Human = Female("tom", 18)
println(h.work())
println(h is Human)
println((h as Female).sleep())
}
5.智能类型转换
如果类型转换过,下次使用时不再需要转换
代码语言:javascript复制fun main() {
val h: Human = Female("tom", 18)
println(h.work())
println(h is Human)
println((h as Female).sleep())
println(h.sleep())
}
6.超类
kotlin中所有类的超类为Any,编译时才会实现它的基本方法,以便根据不同平台实现跨平台