一.对象

        

1.object关键字

        使用object关键字,你可以定义一个只能产生一个实列的类-单例

1.对象声明

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

//object   表示单例
object ApplicationSingle {
    init {
        print("ApplicationSingle")
    }

    fun setMatter(){
        print("setMatter")
    }
}


fun main() {
    print(ApplicationSingle)
    ApplicationSingle.setMatter()
}

2.对象表达式

        有时候你要使用一个类的实例,只用一次,那么对于这种用完就丢的类实例,连命名都可以省了。下面这个例子中对象表达式XX类的子类,使用object关键字后,一旦实例化,该匿名类只能有唯一一个实例存在。

//父类
open class Player{
    open fun load()="loading nothing.."

}

fun main(){
    //对象表达式
    //匿名内部类 单例  继承子类
    val p=object : Player(){
        override fun load()="anonymous class"
    }
    print(p.load())
}

3.伴生对象

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

class ConfigMap {
    //伴生对象为一  且只有调用时才会创建  也是静态
    companion object{
        private const val PATH="xxxx"

        fun load()= File(PATH).readBytes()
    }

}

fun main() {

    ConfigMap.load()
}
 

二.类

1.嵌套类

        如果一个类只对另一个类有用,那么将其嵌入到该类中并使用两个类保持在一起是合乎逻辑的,可以使用嵌套类。

class ImplantClass {
    //嵌套类
    class Equipment(var name:String){
        fun show()= print("equipment:$name") // STOPSHIP: 2021-09-11

    }
    fun battle(){}

}

fun main(){
    //链式调用
    ImplantClass.Equipment("xiaohua").show()
}

2.数据类

1.定义

        数据类,就是用来存储数据的类。 数据类直接提供了toString方法的实现。

        数据类不能使用abstractopnesealedinner修饰符

       ==符号默认情况下,比较两个普通类对象就是比较他们的引用值,数据类默认情况下提供了equals和hashCode函数的实现。、

data class Coordinate (var x:Int,var y:Int){

    private val isInBounds=x>0 && y>0
    //重写
    override fun toString(): String {
        return "Coordinate(x=$x, y=$y, isInBounds=$isInBounds)"
    }

}

fun main() {

    print(Coordinate(10,20))
    //data 类比较的是值
    //class 类比较的是内存地址
    print(Coordinate(10,20)==Coordinate(10,20))
    val coordinate = Coordinate(10, 20)
}

2.copy

        除了重写Any类的部分函数,提供更好用的默认实现外,数据类还提供了一个函数,它可以用来方便地复制一个对象。假设你想创建一个Student实列,除了name属性,它拥有和另一个现有Student实例完全一样的属性值,如果Student是个数据类,那么复制现有Student实列就很简单了,只要调用copy函数,给想修改的属性传入值就可以了。

data class Coordinate (var x:Int,var y:Int){

    private val isInBounds=x>0 && y>0

    init {
        println("initializing student")
    }
    
    constructor(_x:Int):this(_x,20){

    } 

    //重写
    override fun toString(): String {
        return "Coordinate(x=$x, y=$y, isInBounds=$isInBounds)"
    }

}

fun main() {
    val coordinate = Coordinate(10, 20)
    //copy 只能复制主构造函数的属性
    val copy = coordinate.copy(20)
    print(coordinate)
    print(copy)
}

        

3.解构

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

class PlayerScore (private val experience:Int, private val level:Int) {
    //普通类的结构分解 要添加逐渐函数
    operator fun component1()=experience
    operator fun component2()=level
}

fun main() {

   val  (x,y)=PlayerScore(10,20)
    print("$x    $y ")
    //data  类可以直接结构
     val (a,s)=Coordinate(10,20)
    print("$a    $s")
}

4.运算符重载

        如果要将内置运算符应用在自定义类(普通类也可以)身上,你必须重写运算符函数,告诉编译器该如何操作自定义类。

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 coordinate2 = Coordinate2(10, 20)
    val coordinate1 = Coordinate2(10, 20)
    //这里触发重写的plus方法 把两个类的x与y相加
    println(coordinate2+coordinate1 )
}

常用操作符:

操作符

函数名

作用

+

plus

把一个对象添加到另一个对象里

+=

plusAssign

把一个对象添加到另一个对象里,然后将结果赋值给第一个对象

==

equals

如果两个对象相等,则返回true,否则返回false

>

compareTo

如果左边的对象大于右边的对象,则返回true,否则返回false

[ ]

get

返回集合中指定位置的元素

..

rangeTo

创建一个range对象

in

contains

如果对象包括在集合里,则返回true

3.枚举类

1.定义

        枚举类,用来定义常量集合的一种特殊类。

enum class Direction {
    EAST,
    WEST,
    SOUTH,
    NORTH;
  
}

fun main() {
    //这些皆为此类的实例
    print(Direction.EAST)
    print(Direction.EAST is Direction)
}

    当然枚举类也可以定义函数。

enum class Direction(private val coordinate: Coordinate) {
    EAST(Coordinate(1,0)),
    WEST(Coordinate(-1,0)),
    SOUTH(Coordinate(-1,0)),
    NORTH(Coordinate(1,0));
    //有传值需求的话可以用封装类
    var licenseId :String?=null
    fun  updateCoordinate(playerCoordinate: Coordinate)
    =Coordinate(playerCoordinate.x+coordinate.x,playerCoordinate.y+coordinate.y)
}


fun main() {
    //调用函数时,使用的是枚举常量,所以应该这样调用
    print(Direction.EAST.updateCoordinate(Coordinate(10,20)))
  
}

    

2.代数数据类型

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

enum class Direction(private val coordinate: Coordinate) {
    EAST(Coordinate(1,0)),
    WEST(Coordinate(-1,0)),
    SOUTH(Coordinate(-1,0)),
    NORTH(Coordinate(1,0));
    //有传值需求的话可以用封装类
    var licenseId :String?=null
    fun  updateCoordinate(playerCoordinate: Coordinate)
    =Coordinate(playerCoordinate.x+coordinate.x,playerCoordinate.y+coordinate.y)
}

class  Driver(var status : Direction){
    fun checkLicense():String{
        return when(status){
            Direction.EAST->"没资格"
            Direction.WEST->"入学"
            Direction.SOUTH->"学习"
            Direction.NORTH->"有资格 ${status.licenseId}"
        }
    }
}


fun main() {
    print(Driver(Direction.EAST).checkLicense())
}

4.密封类

        对于更复杂的ADT,你可以使用Kotlin的密封类(sealed class)来实现更复杂的定义,密封类可以用来定义一个类似于枚举类的ADT,但你可以更灵活地控制某个子类型。

        密封类可以有诺干个子类,要继承密封类,这些子类必须和它定义在同一个文件里

//密封
sealed class LicenseStatus2 {
    //这里他没使用的必要 没有属性,如果用class的话浪费内存
    object UnQualified : LicenseStatus2()
    object Learning : LicenseStatus2()
    class Qualified(val name:String) : LicenseStatus2()

}


class Driver2(var status :LicenseStatus2){
    fun checkLicense():String{
        return when(status){
            is LicenseStatus2.UnQualified->"没资格"
            is LicenseStatus2.Learning->"在学"
            is LicenseStatus2.Qualified->"有资格,驾驶证编号:${(this.status as LicenseStatus2.Qualified).name}"
        }
    }
}

fun main() {

    print(Driver2(LicenseStatus2.Qualified("20000817")).checkLicense())
}

二.接口

1.接口定义

        Kotlin规定所有的接口属性和函数实现都要使用override关键字,接口中定义的函数并不需要open关键字修饰,他们默认就是open的。

interface Movable {
 
    fun move()
}

class Car :Movable{

    override fun move() {
      
    }

}

2.默认实现

                在接口提供默认属性的getter方法和函数实现。

interface Movable {
     val maxSpeed: Int
         get() = (1..500).shuffled().last()
        var wheels:Int
    //get() = (1..500).shuffled().last()
    fun move(movable: Movable):String
}

class Car(override var wheels: Int=4) :Movable{

    override val maxSpeed: Int
        get() = super.maxSpeed
        
    override fun move(movable: Movable): String {
        return " "
    }

}

三.抽象类

1.抽象类定义

        要定义一个抽象类,你需要在定义之前加上abstract关键字,除了具体的函数实现,抽象类也可以包括抽象函数——只有定义,没有函数实现。

abstract class Gun(val range: Int) {

    abstract fun trigger(): String
}

class M16(_price: Int) : Gun(range = 80) {
    override fun trigger(): String {
        return "M16 shooting"
    }

}

fun main() {
    val g: Gun = M16(120)
    println(g.trigger())
}

下一篇: Kotlin基础 泛型

Logo

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

更多推荐