程诺陪你学Android

Kotlin学习5

2021-05-19  本文已影响0人  flynnny

继承与重载的open关键字

类默认都是封闭(final)的,要让某个类开放继承,必须使用open关键字修饰他

open class Product(val name:String){
  fun des() = "Product: $name"
  //父类的函数也要以open关键字修饰,子类才能覆盖它
  open fun load() ="nothing..."
}
class LuxProduct :Product("Luxury"){
  override fun load() = "luxProduct loading..."//父类方法没用open会报错
}

fun main(){
  val p :Product = LuxuryProduct()
  println(p.load()) 
}

类型转换(as关键字)

kotlin的is关键字用来检测某个对象的类型

open class Product(val name:String){
  fun des() = "Product: $name"
  //父类的函数也要以open关键字修饰,子类才能覆盖它
  open fun load() ="nothing..."
}
class LuxProduct :Product("Luxury"){
  override fun load() = "luxProduct loading..."//父类方法没用open会报错

  fun special() = "LuxProduct  special"
}


fun main(){
  val p= LuxuryProduct()
  println(p is LuxuryProduct) //true
  println(p is Product) //true

//as 关键字
  if(p is LuxuryProduct){
    println((p as LuxuryProduct).special())
  }
}

智能类型转换

kotlin编译器,只要确定any is 父类条件检查属实,他就会将any当做子类类型对待,因此允许你不经类型转换直接使用

println((p as LuxuryProduct).special())//转一次就不需要再转了
println(p.special())

Any超类

kotlin共同继承一个Any超类,java里的Object类

println(p is Any) //true

object关键字

使用object关键字,可以定义一个只能产生一个实例的类--单例
使用object关键字有三种方式
对象声明
对象表达式
伴生对象

对象声明

对象声明有利于组织代码和管理状态,尤其是管理整个应用运行生命周期内的某些一致性状态

object ApplicationConfig{
  init{
    println("loading config ...")
  }
  fun setSomething(){
    println("setSongthing")
  }
}
fun main(){
  //ApplicationConfig即是类名又是实例名字
  ApplicationConfig.setSomething()
  pringln(ApplicationConfig)
  pringln(ApplicationConfig)
}

对象表达式

有时候不一定非要定义一个新的命名类不可,也许你需要某个现有类的一种变体实例,但只需要一次就行了,事实上,对于这种用完就丢的类实例,连命名都可以省了。这个对象表达式是xx的子类,这个匿名类依然遵循object关键字的一个规则,即一旦实例化,该匿名类只能有唯一一个实例存在

open class Player{
  open fun load() = "loading nothing."
}
fun main(){
  val p = object:Player(){
    override fun load()="anonymous class load..."
  }
  println (p.load())
}

伴生对象

如果你想将某个对象的初始化和一个类实例捆绑在一起,可以考虑使用伴生对象,使用companion修饰符,你可以在一个类定义里声明一个伴生对象,一个类只能有一个伴生对象。

import java.io.File

open class ConfigMap{
  //只有初始化ConfigMap类或调用load函数时,伴生对象的内容才会载入
  //而且无论实例化多少次,这个伴生对象只能有一个实例存在
  companion object{
    private const val PATH = "xxx"
    fun load() =FIle(PATH).readBytes()
  }
}
fun main(){
  //static
  ConfigMap.load()
}

嵌套类

一个类只对另一个类有用,那么将其嵌入到该类中并使这两个类保持在一起。

class Player2(){
  class Equipment(var name:String){
    fun show() = printin("$name")
  }
}
fun main(){
  //这里Player2.Equipment()就可以了
  Player2.Equipment("AK47").show()
}

数据类

专门设计用来存储数据的类
数据类型提供了toString的个性化实现
==符号默认是比较引用值,数据类型提供了equals和hashCode的个性化实现

data class Coordinate(var x:Int,var y:Int){
  val isInBounds = x>=0 && y>=0
}
fun main (){
  println(Coordinate(1,5)) //Coordinate(x=1,y=5)
  //==比较的是内容,equals 默认是===
  //===比较的是引用
  println(Coordinate(1,5)==Coordinate(1,5))//true 如果Coordinate类不加data是false
  
}

copy函数

方便的复制一个对象。

data class Student(var name:String ,val age :Int){
  var score = 10;
  private val hobby = "music"
  val subject :String
  init{
    println("init student")
    subject = "math"
  }
  constructor(_name:String):this(_name,10){
    score = 20
  }
  override fun toString ():String{
    return "Student(name='$name', age = $age,"+
                "score=$score, hobby=' $hobby',"+
                "subject='$subject')"
  }
}
fun main(args:Array<String>){
  val s = Student("jack")
  val copy = s.copy("Rose")
  println(copy)//Student(name = 'Rose',age = 10,...)
}

copy函数有个小坑:次构造函数里如果对某个属性作了更改,新的copy对象是没有改的!!!!

解构声明

解构声明的后台实现就是声明component1、component2等若干个组件函数,让每个函数负责管理你想反回的一个属性数据,如果你定义一个数据类,他会自动为所有定义在主构造函数的属性添加对应的组建函数

class PlayerScore(val exp:Int , val level:Int){
  //固定是component1和component2
  operator fun component1() = exp
  operator fun component2() = level
}

fun main(){
  val (x,y) = PlayerScore(10,20)
}

数据类直接支持解构语法

运算符重载

13.png
data class Coordinate2(var x:Int,var y :Int){
  val isInBounds = x>=0&&y>=0

  operator fun plus(other:Coordinate2)=
        Coordinate2(x +other.x,y+other.y)
}
fun main(){
  val c1 = Coordinate2(5,6)
  val c2 = Coordinate2(10,20)
  println(c1+c2)
}

枚举类

enum class Dir{
  EAST,
  WEST,
  SOUTH,
  NORTH
}
fun main(){
  println(Dir.EAST)//EAST
}

枚举类定义函数

//给枚举类添加一个柱构造函数
enum class Dir2(private val coordinate:Coordinate){
  //因为枚举类的构造函数都带参数,所以定义每个枚举类常量时
  //都要传入Coordinate对象,调用构造函数
  EAST(Coordinate(5,-1)),
  WEST(Coordinate(1,0)),
  SOUTH(Coordinate(0,1)),
  NORTH(Coordinate(-1,0));
  
  fun updateCoordinate(playerC:Coordinate) =
    Coordinate(playerC.x+coordinate.x,
                      playerC.y+coordinate.y)
}
fun main(){
  pringln(DIr2.EAST.updateCoordinate(Coordinate(10,20)))
}

代数数据类型

可以用来标识一组子类型的闭集,枚举类就是一种简单的ADT

enum class Liscen{
  UNQUALIFIED,
  LEARNING,
  QUALIFIED;
}
class Drive(var status :Liscen){
  fun check() :String{
    //不使用else,且编译器会帮你检查遗漏
    return when (status){
      Liscen.UNQUALIFIED->"没资格"
      Liscen.LEARNING->"在学"
      Liscen.QUALIFIED->"有资格"
    }
  }
}

密封类(sealed class)

密封类实现更复杂的ADT。
密封类可以有若干个子类,要继承密封类,这些子类必须和他定义在同一个文件里

sealed class Lic2{
  object UnQualified :Lic2()
  object Learning:Lic2()
  class Qualified(val licenseId:String):Lic2()
}
class Drive2(var status:Lic2){
  fun check():String{
    return when(status){
      is Lic2.UnQualified ->"没资格"
      is Lic2.Learning ->"在学"
      is Lic2.Qualified ->"有资格,编号:"+
          "${(this.status as Lic2.Qualified).licenseId}"
    }
  }
}
fun main(){
  val status = Lic2.Learning
  val driver = Driver2(status)
  println(driver.check())

  val status2 = Lic2.Qualified("12312") 
  val driver2 = Driver2(status)
  println(driver2.check())
}

使用数据类条件

14.png

小结

上一篇下一篇

猜你喜欢

热点阅读