Kotlin基础 定义类与初始化、继承
一.定义类1.field针对你定义的每一个属性,Kotlin都会产生一个field,一个getter,以及一个setter,field用来存储属性数据,你不能直接定义field,Kotlin会封装field,保护它里面的数据,只暴露给getter和setter使用。属性的getter方法决定你如何读取属性值,每个属性都有getter方法,setter方法决定你如何给属性赋值,所以只有可变属性才会有
一.定义类
1.field
针对你定义的每一个属性,Kotlin都会产生一个field,一个getter,以及一个setter,field用来存储属性数据,你不能直接定义field,Kotlin会封装field,保护它里面的数据,只暴露给getter和setter使用。属性的getter方法决定你如何读取属性值,每个属性都有getter方法,setter方法决定你如何给属性赋值,所以只有可变属性才会有setter方法,尽管Kotlin会自动提供默认的getter和setter方法,但在需要控制如何读写属性数据时,你也可以自定义他们。
class Player{
var name="XiaoHua"
get()=field.capitalize()
private set(value) {
field=value.trim()
}
var age=10
get() = field.absoluteValue
set(value) {
field=value.absoluteValue
}
}
2.计算属性
计算属性是同过一个覆盖的get或set运算符来定义,这时field就不需要了。
class Player {
var calculateValue
get() = (1..10).shuffled().first()
}
二.初始化
1.主构造函数
我们在Player类的定义头中定义一个主构造函数,使用临时变量为Player的各个属性提供初始值,而在Kotlin中,为了便于识别,临时变量(包括仅引用一次的参数),通常都会以下划线开头的名字命名。
class Player (
_name : String,
_age : Int,
_isNormal : Boolean
){
var name=_name
get()=field.capitalize()
private set(value) {
field=value.trim()
}
var age=_age
get() = field.absoluteValue
set(value) {
field=value.absoluteValue
}
var isNormal=_isNormal;
}
2.在主构造函数里定义属性
Kotlin允许你不使用临时变量赋值,而是直接用一个定义同时指定参数和类属性,通常,我们更喜欢用这种方式定义类属性,因为他会减少重复代码。
class Player2(
_name : String,
var age : Int,
var isNormal : Boolean
){
var name=_name
get()=field.capitalize()
set(value) {
field=value.capitalize()
}
}
3.次构造函数
次构造函数对应主构造函数,我们可以定义多个此构造函数来配置不同的参数组合,我们也可以在此构造函数里初始化代码。
class Player2(
_name : String,
var age : Int,
var isNormal : Boolean
){
var name=_name
get()=field.capitalize()
set(value) {
field=value.capitalize()
}
//次级构造函数
constructor(name:String):this(name,age=100,isNormal=true)
//此构造函数初始化
constructor(name:String,age:Int):this(name,age=100,isNormal=true){
this.name=name.capitalize()
}
}
4.默认参数
定义构造函数时,可以给构造函数参数指定默认值,如果用户调用时不提供值参,就使用这个默认值
class Player3(
_name : String,
var age : Int=20,
var isNormal : Boolean
){
var name=_name
get()=field.capitalize()
set(value) {
field=value.capitalize()
}
}
5.初始化
初始化块可以设置变量或值,以及执行有效性检查,如检查给某构造函数的值是否有效,初始化代码会在构造类实例时执行。
//静态代码块
init {
//不满足条件 抛异常
require(age>0){ "age muse be positive" }
require(name.isNotBlank()){"player muse have"}
}
6.初始化顺序
1. 主构造函数里声明的属性
2.成员属性赋值
3.init初始化块里的属性赋值和函数调用
4.次构造函数里的属性赋值和函数调用

7.延迟初始化
使用lateinit关键字相当于做了一个约定:再用它之前负责初始化
只要无法确认lateinit变量是否完成初始化,可以执行isInitialized检查
class Player4 {
//延迟初始化
lateinit var equipment :String
fun ready(){
equipment="aaaa"
}
fun battle(){
//检查是否初始化
if (::equipment.isInitialized){
print(equipment)
}
}
}
fun main() {
val player4 = Player4()
player4.ready()
player4.battle()
}
8.惰性初始化
延迟舒适化并不是推后初始化的唯一方式,你也可以暂时不初始化某个变量,直到首次使用它,这个叫做惰性初始化。
class Player5(_name:String) {
var name=_name
val config by lazy { loadConfig() }
private fun loadConfig():String{
print("loading.....")
return "Asdsad"
}
}
fun main() {
val p = Player5("xiaohua")
print(p.config)
}
9.初始化陷阱
1.
在使用初始化块时,顺序非常重要,你必须保证块中的所有属性已经完成初始化。

2.
这段代码编译没有问题,因为编译器看到name属性已经在init块里初始化了,但代码一运行,就会抛出空指针异常,因为name属性还没赋值,firstLetter函数就应用它了。
class Player7() {
val name:String
private fun firstLetter()=name[0]
init {
println(firstLetter())
name="XiaoHua"
}
}
3.
因为编译器看到所有属性都初始化了,所以代码编译没问题,但运行结果却是null,问题出在
initPlayerName函数初始化playerName时,name属性还未完成。
class Player8(_name: String) {
val playerName:String=initPlayerName();
val name:String=_name
private fun initPlayerName()=name;
}
三.继承
1.继承
类默认都是封闭的,要让某个类开放继承,必须使用open关键字修饰它。
//父类标志 open
open class Product (val name:String){
fun description()="Product: $name"
//open 要继承的方法也需要
open fun load()="Nothing..."
}
class LuxuryProduct :Product("Luxury"){
}
2.函数重载
父类的函数也要以open关键字修饰,子类才能覆盖它。
//父类标志 open
open class Product (val name:String){
fun description()="Product: $name"
//open 要继承的方法也需要
open fun load()="Nothing..."
}
class LuxuryProduct :Product("Luxury"){
//override 重写
override fun load()="LuxuryProduct loading..."
}
3.类型测试
Kotlin的is运算符可以检查属性类型
//父类标志 open
open class Product (val name:String){
fun description()="Product: $name"
//open 要继承的方法也需要
open fun load()="Nothing..."
}
class LuxuryProduct :Product("Luxury"){
//override 重写
override fun load()="LuxuryProduct loading..."
fun special()="aaaaaaaaaaaaaaaaaa"
}
fun main() {
//kotlin 多态
val luxuryProduct:Product = LuxuryProduct()
print(luxuryProduct.name)
// 判断 类型检查
print(luxuryProduct is Product)
print(luxuryProduct is LuxuryProduct)
print(luxuryProduct is File)
}
4.类型转换
as操作符声明,这是一个类型转换
//父类标志 open
open class Product (val name:String){
fun description()="Product: $name"
//open 要继承的方法也需要
open fun load()="Nothing..."
}
class LuxuryProduct :Product("Luxury"){
//override 重写
override fun load()="LuxuryProduct loading..."
fun special()="aaaaaaaaaaaaaaaaaa"
}
fun main() {
//kotlin 多态
val luxuryProduct:Product = LuxuryProduct()
print(luxuryProduct.name)
//这里说明类的类型只用转一次 之后不用在转
print((luxuryProduct as LuxuryProduct).special() )
print(luxuryProduct.special() )
}
5.智能类型转换
Kotlin编译器很聪明,子要能确定any is父类条件检查属实,他就会将any当作子类
类型对待,因此,编译器运行你不经类型转换直接使用。
//父类标志 open
open class Product (val name:String){
fun description()="Product: $name"
//open 要继承的方法也需要
open fun load()="Nothing..."
}
class LuxuryProduct :Product("Luxury"){
//override 重写
override fun load()="LuxuryProduct loading..."
fun special()="aaaaaaaaaaaaaaaaaa"
}
fun main() {
//先判断
if (luxuryProduct is LuxuryProduct){
//这因为是用了多态 创建的对象指向父类引用 而父类无法调用子类的方法 所以要转换
print(luxuryProduct.special() )
}
}
6.Kotlin层次
在Kotlin中每个类都会继承一个叫做Any的超类(类似java中的Object)
更多推荐



所有评论(0)