学习笔记-kotlin(6)

目录

1.对象

1.1.嵌套类

1.2.数据类

1.3.枚举类

1.4.运算符重载

1.5.密封类

2.接口 

3.抽象类

在这里感谢Jason老师。我是他学生。

1.对象

1.1.嵌套类

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

    //嵌套类
    class Player2() {
        class Equipment(var equipName:String) {
            fun showEquip() {
                println("Equipment: $equipName")
            }
        }

        fun battle() {
            Equipment("knife").showEquip()
        }
    }

    fun qiantaoTest() {
        Player2.Equipment("比尔特弯刀").showEquip()
        Player2().battle()
    }

 运行结果:Equipment: 比尔特弯刀
                   Equipment: knife

可以看到这两种用法都可以。

1.2.数据类

        1.数据类使专门用来设计存储数据的。2.提供了toString、equals和hashCode的个性化实现。3.==符号默认情况使比较它们的引用值。

    //数据类
    data class Coordinate(var x:Int, var y:Int) {

    }

    fun dataTest() {
        println(Coordinate(10, 100))
    }

运行结果:Coordinate(x=10, y=100)

data默认实现了toString函数,所以输出的会与Any不同。 

4.数据类还提供了一个函数,可以方便的复制一个对象,copy还可以选择的修改其中要修改的值。

    //copy   坑点:copy的时候走的是主函数,如果有些属性在次构造有调整,那么就会出现不同
    data class Student(val name:String, var age:Int) {
        var score = 56;
        var subject = "math"

        override fun toString(): String {
            return "Student(name='$name', age=$age, score=$score, subject='$subject')"
        }
    }

    fun copyTest() {
        var s = Student("huahua", 24);
        println(s)
        println(s.copy(name = "jack"))
    }

运行结果:Student(name='huahua', age=24, score=56, subject='math')
                  Student(name='jack', age=24, score=56, subject='math')

其中的坑点是:如果你要copy一个次构造函数实例的对象,并且有些属性在次构造里修改。那么copy出来的值将会是不同的。详细可以见字节码,大家可以试试。

5.支持解构。

    //解构
    class PlayerScore(var score:Int, var level:Int) {
        operator fun component1() = score;
        operator fun component2() = level;
    }

    fun jiegouTest() {
        val (x1, x2) = PlayerScore(56, 2)
        println("x1 = ${x1}; x2 = $x2")
    }
@Metadata(
      mv = {1, 5, 1},
      k = 1,
      d1 = {"..."},
      d2 = {...}
   )
   public static final class PlayerScore {
      private int score;
      private int level;

      public final int component1() {
         return this.score;
      }

      public final int component2() {
         return this.level;
      }

      public final int getScore() {
         return this.score;
      }

      public final void setScore(int var1) {
         this.score = var1;
      }

      public final int getLevel() {
         return this.level;
      }

      public final void setLevel(int var1) {
         this.level = var1;
      }

      public PlayerScore(int score, int level) {
         this.score = score;
         this.level = level;
      }
   }

运行结果: x1 = 56; x2 = 2

这不是数据类,没有被data修饰。这是普通类的解构方式,看字节码我们可以看出解构的有用component修饰,数据类默认是给我们提供了结构的。详情看字节码。

   public static final class Student {
      private int score;
      @NotNull
      private String subject;
      @NotNull
      private final String name;
      private int age;

      ........

      @NotNull
      public String toString() {
         return "Student(name='" + this.name + "', age=" + this.age + ", score=" + this.score + ", subject='" + this.subject + "')";
      }

      @NotNull
      public final String getName() {
         return this.name;
      }

      public final int getAge() {
         return this.age;
      }

      public final void setAge(int var1) {
         this.age = var1;
      }

      public Student(@NotNull String name, int age) {
         ......
      }

      @NotNull
      public final String component1() {
         return this.name;
      }

      public final int component2() {
         return this.age;
      }

      @NotNull
      public final ObjectTest.Student copy(@NotNull String name, int age) {
         .....
      }

      // $FF: synthetic method
      public static ObjectTest.Student copy$default(ObjectTest.Student var0, String var1, int var2, int var3, Object var4) {
         ......
      }

      public int hashCode() {
         ......
      }

      public boolean equals(@Nullable Object var1) {
         ....
      }
   }

这是上边Student的字节码,看到这个就证明了刚才所述。1.数据类输出不一样是重载了toString;2.我们也可以重载equals和hashCode来实现自己的需求;3.并且有解构component;4.copy方法。

数据类注意项:

        1.必须有至少带有一个参数的主构造函数

        2.主构造函数里的参数不能为临时变量,一定要var/val 修饰的变量

        3.不能使用abstract、open、sealed和inner修饰。

1.3.枚举类

    //枚举类
    enum class Direct {
        EAST,
        WEST,
        SOUTH,
        NORTH
    }

    fun enumTest() {
        println(Direct.NORTH)
    }

运行结果:NORTH

枚举类也能定义函数和自定义函数 

    //数据类
    data class Coordinate(var x:Int, var y:Int) {

    }

    //枚举类有主构造函数 和 自定义的函数
    enum class Direction(private var coordinate: Coordinate) {
        EAST(Coordinate(1, 1)),
        WEST(Coordinate(2, 2)),
        SOUTH(Coordinate(3, 3)),
        NORTH(Coordinate(4, 4));

        fun updateCoordinate(cdinate:Coordinate) : Coordinate {
            return Coordinate(coordinate.x + cdinate.x, coordinate.y + cdinate.y)
        }
    }

    fun enumTest2() {
        println(Direction.EAST.updateCoordinate(Coordinate(20, 20)))
    }

运行结果:Coordinate(x=21, y=21)

其中可以能不太理解EAST、WEST、SOUTH和NORTH为啥这么写,你可以理解EAST...都是Direction的实例,然后我们给枚举类定义了主构造函数,所以要传参。

1.4.运算符重载

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

    //运算符重载
    data class Coordinate2(var x:Int, var y:Int) {
        operator fun plus(other:Coordinate2):Coordinate2 {
            return Coordinate2(x + other.x, y + other.y)
        }
    }

    fun dataTest2() {
        val coordinate = Coordinate2(1, 2)
        val coordinate2 = Coordinate2(2, 3)
        println(coordinate + coordinate2)
    }

运行结果:Coordinate2(x=3, y=5)

这边我重载的方法是 +。其他的大家可以自行试试。重载的时候记得加operate修饰

 操作符所对应的函数名,大家可去官网自行查阅。我这边写几个对应的:

操作符函数名
+plus
+=plusAssign
==equals
>compareTo
[]get
..rangeTo
incontains

1.5.密封类

    //密封类
    sealed class LicenseStatus {
        object UnQualified : LicenseStatus()
        object Learning : LicenseStatus()
        class Qualified(val licenseId:String) : LicenseStatus()
    }

    class Police(private val licenseStatus: LicenseStatus) {
        fun checkLicense() : String {
            return when(licenseStatus) {
                is LicenseStatus.UnQualified -> "没资格"
                is LicenseStatus.Learning -> "在学"
                is LicenseStatus.Qualified -> "有资格,驾驶证编号:${(this.licenseStatus as LicenseStatus.Qualified).licenseId}"
            }
        }
    }

    fun sealedTest() {
        println(Police(LicenseStatus.Qualified("356431223")).checkLicense())
    }

运行结果:有资格,驾驶证编号:356431223

讲下这个代码的需求场景:警察查驾照,驾照我给的状态是3个,没有、在学和有驾照。其中有驾照就有驾照号,我需要输出查阅驾照号。如果用枚举类,再写一个变量var licenseId:String 那么其他两个状态都有这个变量,都可以对这么变量进行操作,但我只要有驾照才有这个变量,用密封类就比较快,3个类,object修饰类是有单例的效果,之前的学习笔记有讲到。没有驾照和在学习中没有任何属性单例也不太有所谓,有驾照的就class声明一个,但他们都继承自LicenseStatus。然后在做判断的时候要用is判断它具体是什么类。当然我讲的这个需求肯定有比这还好的方法,只是我觉得这样需求比较好描述密封类。

2.接口 

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

    interface EventListener {
        fun clickListenerCallBack(listener: EventListener)
    }

    class Event(_name:String) : EventListener{
        override fun clickListenerCallBack(listener: EventListener) {
            TODO("Not yet implemented")
        }

    }

字节码中没有被final定义,所以咱们说默认是open的。

   public interface EventListener {
      void clickListenerCallBack(@NotNull IntefaceTest.EventListener var1);
   }

3.抽象类

    abstract class Car(val name:String, val speed:Int) {
        abstract fun accelerate() : String
    }

    class Motorcycle() : Car("motorcycle", 100) {
        override fun accelerate(): String {
            return "我的速度是$speed,我的名字是$name"
        }
    }

    fun AbstractTest1() {
        println(Motorcycle().accelerate())
    }

运行结果:我的速度是100,我的名字是motorcycle

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值