初识Kotlin<下>

作者: 我是李小米 | 来源:发表于2017-11-16 16:21 被阅读13次

    上一篇《初识Kotlin<上>》

    在上一篇文章中介绍了Kotlin的一些基本语法,包括变量、常量的定义、控制循环语句、函数的定义及使用、类的定义、方法和属性、继承、数据类、枚举类、异常处理、类型检查和转换等部分的内容。这这篇文章中记录一下接口、泛型以及扩展的部分内容。
    接上篇继续

    8、接口:

    在java语言中也有接口的定义,和kotlin中相比相差不大。那什么是接口呢?
    接口就是对方法或者属性的实现标准。这样说可能有点抽象。举个例子:每一个自然人呢都有一个名字,然后现在有一个歪果仁想要加入中国的国籍,想要以后在中国发展。那咱们定义一个人(Person)的类,然后再定义一个歪果仁(ForigChinese)的类去继承人(Person)的类。
    这时候这个歪果仁要加入中国的国籍,那怎么办呢,我们不能在Person类中添加加入中国国籍的方法。所以我们去写一个接口,定义一个加入中国国籍的方法,让想要加入中国国籍的歪果仁去实现这个方法。这样,这个歪果仁的实例就可以去调用加入中国国籍的方法了。
    具体的咱们来看下边的代码:
    首先定义一个Person类,因为这个类需要被其他的类继承,所以使用open关键字来修饰

       open class Person {
            var name = ""
        }
    

    然后去定义一个可以生存的接口:

        interface Livable {
            //接口中的属性和方法不能初始化
            var hasSkill: Boolean//接口中的属性
            fun addChina() //接口中的方法
            //接口中的方法可以有默认实现,通常指该方法是固定不变的
            fun SpeakChinese() {
                LogUtils.Loge("接口中的默认方法:我可以说中文")
            }
        }
    

    然后定义一个可以在中国生存的接口:

        interface ChinaLivable {
            //接口中的属性不可初始化
            val hasJobOffer: Boolean
            //接口中可以有get方法,通常用于增加一个常量属性
            val visaCatagory: String
                get() = "工作offer"
            //接口中的属性
            var city: String
        }
    

    然后去定义一个歪果仁的类继承Person类,并且实现生存接口和在中国生存的接口:

        class ForigChinese : Person(), Livable, ChinaLivable {
            override var hasJobOffer: Boolean = true
            override var city: String = "北京"
            override var hasSkill: Boolean = true
            override fun addChina() {
                LogUtils.Loge("我叫${name}我要加入中国国籍")
            }
        }
    

    这时候,这个歪果仁就有了生存的能力,并且有了在总过生存的能力。所以他就能加入中国国籍了。

            var mForigChinese = ForigChinese()
            mForigChinese.name = "小米"
            mForigChinese.city = "北京"
            mForigChinese.hasJobOffer = true
            mForigChinese.hasSkill = true
            mForigChinese.addChina()
            mForigChinese.SpeakChinese()
            LogUtils.Loge("接口名称:" + mForigChinese.name)
            LogUtils.Loge("接口城市:" + mForigChinese.city)
            LogUtils.Loge("接口是否有工作:" + mForigChinese.hasJobOffer)
            LogUtils.Loge("接口是否有生存技能:" + mForigChinese.hasSkill)
    

    然后看一下Log:

    11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 我叫小米我要加入中国国籍###
    11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 接口中的默认方法:我可以说中文###
    11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 接口名称:小米###
    11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 接口城市:北京###
    11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 接口是否有工作:true###
    11-16 15:49:22.968 4994-4994/com.example.lql.kotlindemo E/###: 接口是否有生存技能:true###
    

    我们发现我们给歪果仁(ForigChinese )类添加了两个能力,一个是生存的能力,一个是在中国生存的能力,但是ForigChinese类本身看起来并没有复杂。所以,接口可以给 类附加能力,并且让类看起来很简洁。
    还有一点,这个能力并没有在父类中去实现,所以通过接口的方法来实现某些功能,是可以选择的,如果我不想要在中国生存的能力,就可以不实现这个接口就好了。使用起来很方便。

    9、泛型:

    泛型就是让一个函数或者类能更加通用,首先咱们看一下系统给提供的一下泛型的方法。

    //定义一个Int类型的数组
    var intList = arrayOf(1, 2, 3, 4, 5, 6, 7, 10)
    //定义一个String类型的数组
    var stringList = arrayOf("1","2","3","4","5","6","7","9")
    

    我们发现arrayOf方法,我们既可以传Int类型的参数进去,也可以传String类型的参数进去。这就是泛型方法的体现。
    在我们定义方法或者类的时候,有时候也要考虑这个因素进去,我们写了一个工具类,能不能传递不同类型的传输进去呢?这可以让方法在更多的情境下使用。

    9.1基本泛型

    然后我们来看一下泛型在Kotlin中的写法:

        //定义一个泛型函数: <T> T表示一个占位符
        fun <T> showText(para: T) {
            LogUtils.Loge("泛型入参:" + para.toString())
        }
    

    然后调用这个方法:

     showText(3)
    showText("123")
    

    Log:

    11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 泛型入参:3###
    11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 泛型入参:123###
    

    我们可以看到对与一个方法showText()传递了两种不同类型的参数进去。

    9.2约束泛型:

    现在我们有一个数组

    arrayOf(1, 2, 3, 4, 5, 6, 7, 10, 11)
    

    我们相对这个数组求和,这个时候我们参数都是Int类型的,我们可以直接调用.sum()方法去求和。
    然后咱们把数组改一下

    arrayOf(1, 2, 3, 4, 5, 6, 7, 10, 11.11)
    

    这样,里边多了一个double类型的元素。这时候就没办法调用.sum()方法了。然后我们使用约束泛型去实现一个求和方法:

     //下边就是泛型约束:<泛型占位符: 类型>  把泛型约束在Number类型中
        fun <T : Number> sum2(vararg number: T): Double {
            return number.sumByDouble { it.toDouble() }
        }
    

    通过上边的注释,大家应该能看懂这个约束泛型的意思。就不再解释了。

    9.3多重约束泛型:

    写法就是把多个约束用where修饰,中间使用“ , ”隔开,写在函数体之前。
    例子:把数组中大于某个元素的部分都取出来并升序排列

        //Comparable 可比较的,大于、小于、等于
        fun <T> biggerPart(list: Array<T>, threhold: T): List<T>  where T : Number, T : Comparable<T> {
            return list.filter { it >= threhold }.sorted()
        }
    

    来看一下试用方法:

    //多重约束
            val biggerPart = biggerPart(arrayOf(99, 1, 2, -2, 88, 1024, 888), 3)
            for (i in biggerPart) {
                LogUtils.Loge("多重约束:${i}")
            }
    

    Log:

    11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 泛型约束:38.11###
    11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 多重约束:88###
    11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 多重约束:99###
    11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 多重约束:888###
    11-16 16:02:29.258 4994-4994/com.example.lql.kotlindemo E/###: 多重约束:1024###
    

    10、扩展:

    所谓扩展,就是对已经有的类,但是不能修改源码的这种去增加一些方法。添加方法的时候要注意尽量不要和类中已经有的方法重名,如果非要重名,那类型也不要相同。简单来说就是别一毛一样。举个例子:咱们要Toast一下,但是每次写吐司都写的比较长,怎么办呢?咱们就用这个类的扩展,对Context类写一个Toast扩展:

        fun Context.ToastKotlin(message: String) {
            Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
        }
    

    同样使用也很简单(这是一个recyclerview的点击事件):

            mTestAdapter!!.setOnItemClickListener(OnItemClickListener { view, position ->
                this.ToastKotlin("adapter的点击事件${position}")
            })
    

    尴尬的事情出现了,在Kotlin中已经帮咱们写了这个扩展方法了,相信大家调用的时候会发现这个问题,但是大家懂了这个意思就好了。然后咱们看一下其他的例子具体的写法:

    //扩展函数:fun 接受者类型.新扩展函数名(参数类别){//函数实现}
        //1、函数扩展
        fun Int.square(): Int {
            return this * this
        }
    
        //2、泛型函数扩展:求数字型数组中的最大元素
        fun <T> Array<T>.biggest(): T
                where T : Number,
                      T : Comparable<T> {
    
            var biggest = this[0]
            for (t in this) {
                if (t > biggest) {
                    biggest = t
                }
            }
            return biggest
        }
    
    
        //    3、属性的扩展(普通属性)
        val Int.next: Int
            get() = this + 1
    
        //4、泛型属性    数字类型的半径   的面积
        val <T : Number> T.area: Double
            get() = 3.1425926 * this.toDouble() * this.toDouble()
    
    

    使用:

     LogUtils.Loge("函数扩展:" + 3.square())
    
            val a = arrayOf(1, 2, 3, 4, 5, 8)
            LogUtils.Loge("求最大" + a.max())
            val biggest = a.biggest()
            LogUtils.Loge("自己写一个求最大:" + biggest)
    
            LogUtils.Loge("属性扩展:" + 3.next)
            LogUtils.Loge("属性泛型扩展:" + 3.area)
            LogUtils.Loge("属性泛型扩展:" + 'B'.toByte().area)
    

    Log:

    11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 函数扩展:9###
    11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 求最大8###
    11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 自己写一个求最大:8###
    11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 属性扩展:4###
    11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 属性泛型扩展:28.283333399999997###
    11-16 16:16:59.348 4994-4994/com.example.lql.kotlindemo E/###: 属性泛型扩展:13689.1333656###
    

    这一部分,大家一看就知道具体的意思了,就不解释了。

    好啦,通过两篇文章记录了一下Kotlin中变量的定义、元组的使用、循环控制流的使用、类的相关使用、异常处理、接口、泛型和扩展部分的内容。最开始学习Kotli就先聊这么多。我需要继续学习了。还是上一篇中的那句话,刚开始学习使用Kotlin,可能对概念以及用法的认识有偏差,如有错误,希望大家给予指正!

    相关文章

      网友评论

        本文标题:初识Kotlin<下>

        本文链接:https://www.haomeiwen.com/subject/rywlvxtx.html