一.定义类

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)

下一篇: Kolin基础 对象与类、接口

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐