Kotlin的解析(中)

前言

  通过上一篇的Kotlin介绍了一些基本的变量,方法,函数,类等的基本讲解,接下来,让我们更近一步的学习,深入一点的知识

1.  枚举类和扩展

1.1 枚举类

  Kotlin的枚举类和Java的非常相似,具有类的特性,一般会将可枚举的同类型一组值作为枚举类定义,由于每一枚举都是个对象,可能在性能上还是不推荐用,Android中已经用注解慢慢取代了,这种枚举的使用

1.1.1 枚举类的基本用法

  在kotlin中,枚举类型是以类的形式存在的,因此成为枚举类

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

1.1.2 枚举值指定对应的数值
  从下面的代码可以看出,除了基本的语法不同,实现的规则和Java的非常相似

enum class Direction private constructor(val d:Int){ 
    SOUTH(1),WEST(2);

    override fun toString(): String {
        return d.toString()
    }
}

fun main(args:Array<String>){
var dir1 : Direction = Direction. SOUTH
var dir2  = Direction. WEST
println(dir1)//输出的是1
println(dir2)//输出的是2
}

1.1.3 枚举的其他拓展

  var dir1 : Direction = Direction. WEST
        Log.i("tag",dir1.name)//输出的是:WEST
        Log.i("tag",dir1.ordinal.toString()) //输出的是在枚举中的位置 1
        Log.i("tag",dir1.toString()) //输出的是传入的数值
        Log.i("tag",Direction.valueOf("WEST").toString()) //输出的是传入的数值

//如果要得到所有枚举的值,可以使用values的方法
for(d in Direction.values()){
println(d)
}
1.2 扩展

  扩展是Kotlin中非常重要的功能,可以在没有源代码的情况下向类中添加成员,也可以啊子团队开发的情况下,通过扩展,将模块分散给多个人开发

1.2.1 扩展原生API

Kotlin的原生的集合扩展

//这个方法放哪里呢?一般都放在Kotlin文件顶层,当然,也可以放在调用swap方法的位置前面
fun MutableList<Int>.swap(index1:Int ,index2:Int){
            //为MutableList添加一个swap的方法,用于交互任意两个集合元素的位置
            var tmp = this[index1]
            this[index1] = this[index2]
            this[index2] = tmp;
        }

val tab = mutableListOf(1,2,3)
        tab.swap(0,2) //原生里面是没有这个方法的,通过扩展就可以了,牛逼
        Log.i("tag","jihe:  " + tab.toString())//输出[3,2,1]

JDK标准的集合类ArrayList添加了一个hellow的方法

 fun ArrayList<Int>.hellow(string: String){
            println(string)
        }

        var list: ArrayList<Int> = ArrayList();
        list.add(20)
        list.add(30)
        list.add(40)
        list.add(50)
        list.swap(0,2)//这个是原生自带的
        list.hellow("牛逼吧!!!嘻嘻") //这个是上面自己写的一个方法

1.2.2 扩展自定义类
  扩展类的目的很多,除了系统类需要扩展之外,我们自己编写的类有时候也需要扩展,但是我们有不想去类里面修改,这时候这个功能就相得益彰

open class Parent(val va1: Int, val va2: Int) {//使用open声明,才能允许其他类继承
    var mVal1 = va1
    var mVal2 = va2
    fun add() = this.mVal1 + this.mVal2
}

class Child(va1: Int, va2: Int) : Parent(va1, va2) {
    fun sub() = mVal1 - mVal2
}


        fun Parent.log() {
            Log.i("tag", "父类:" + "${mVal1} +${mVal2} = ${add()}")
        }

        fun Child.log() {
            Log.i("tag", "子类:" + "${mVal1} -${mVal2} = ${sub()}")
        }

        var par1: Parent = Parent(1, 2)
        var par2: Parent = Child(1, 2)
        var chil1: Child = Child(1, 2)

        par1.log()//父类:1 +2 = 3
        par2.log()//父类:1 +2 = 3
        chil1.log()//子类:1 -2 = -1



open class Parent(val va1: Int, val va2: Int) {
    var mVal1 = va1
    var mVal2 = va2
    fun add() = this.mVal1 + this.mVal2
//内部成员函数,和扩展同名,扩展覆盖不了内部
fun log() {
        Log.i("tag", "父类:自己" + "${mVal1} +${mVal2} = ${add()}")
    }
}


fun Parent.log() {
            Log.i("tag", "父类:" + "${mVal1} +${mVal2} = ${add()}")
        }

        fun Child.log() {
            Log.i("tag", "子类:" + "${mVal1} -${mVal2} = ${sub()}")
        }

        var par1: Parent = Parent(1, 2)
        var par2: Parent = Child(1, 2)
        var chil1: Child = Child(1, 2)

        par1.log()//父类:自己1 +2 = 3
        par2.log()//父类:自己1 +2 = 3
        chil1.log()//父类:自己1 +2 = 3
 

  上面可以看出:(1)尽管par2的实例对象是Child,但是通过扩展的方法,并没有重写父类的扩展方法,因此par2调用的还是父类的方法。
(2)类内部成员函数和通过扩展添加的成员函数冲突,那么内部成员函数的优先级更高,通过扩展无法覆盖内部成员函数

1.2.3 扩展伴随对象
  如果类中有伴随对象(由于Kotlin类不支持静态成员变量,因此引入了伴随对象,来解决类没有静态成员所带来的尴尬),那么可以利用扩展对象添加成员

class SubClass  {
    companion object {
    }
}

fun  SubClass.Companion.nihao(){
           Log.i("tag","hello word!")
        }

SubClass.nihao();//不需要实例,直接类名调用
//扩展范围,放大
//在类中也可以使用扩展

2.  数据类和封装

  数据类和封装是Kotlin中两种特殊的类,前者用于描述数据和相应的操作,后者相当于枚举类的扩展,用于描述有限的数据

2.1 数据类

  数据类是Kotlin 的一个语法糖,Kotlin编译器会自动为数据类生产一些成员函数,以提高开发效率

2.1.1 使用数据类

//一般的类的书写
class User(var name: String, var sex: Int)  {
    var mName = name
    var mSex = sex
    override fun equals(other: Any?): Boolean {
    //重写,是不是感觉的很不爽,要写这么多
        if (other is User) {
            if (mName == other.mName && mSex == other.mSex) {
                return true
            }
        } else {
            return false
        }
        return false
    }
    override fun toString(): String {
      //重写,是不是Java中很烦,yes,很烦
        return "User {name = $mName \n sex = $mSex }"
    }
}

  从上面User可以看出,只有name和sex是必要的,其余的都可以自动的推倒,而怎么弄呢?其实Kotlin中提供了,那就是在class前面加上data关键字就行了

data class Student(var name: String) {
    constructor():this("sdfdf")//为了添加一个无参的构造函数
}

var student = Student("xixi")
var student1 = Student("haha")
Log.i("tag", student.toString()); //输出:Student(name=xixi)
Log.i("tag", student1.toString());//输出: Student(name=haha)
Log.i("tag", student.equals(student1).toString());//输出:false

  数据类和普通的类最大的不同,就是数据类可以根据构造器的参数自动生成相关的代码;如果Kotlin中,同事具有普通类,以及存储和管理数据的功能,建议直接使用数据类

编写数据类注意事项
(1)主构造器至少有一参数
(2)主构造器的参数必须标记为var/val
(3)数据类不能是抽象类,open类,封闭类(sealed)类或内部类(inner)
由于主构造器必须要有一个参数,不可能存在没有参数的主构造器,要想拥有,两种方案解决:
(1)为主构造器每个参数都加上默认值

data class User(val name :String="Bill", var age :Int = 10)

(2)添加一个没有参数的构造器,调用主构造器时,指定默认参数

data class User(var name : String ,var age :Int){
//次构造函数
constructor():this("Devin","18")
}

2.1.2 数据类成员的解构
  数据类成员解构,这里关键解构,也就是解除结构,在数据类中,用属性表示数据,这些属性属于同一数据类,要想使用这些属性,必须首先引用数据对象,这里的解构就是指将这些数据对象的属性提取出来,分别单独赋值给变量

  var student = Student("大家好")
  val (name) = student
  Log.i("tag", ";;;;;;"+name );//;;;;;;大家好

2.1.3 封闭类
  封闭类也是Kotlin的一个语法糖,可以把它理解为枚举的扩展,一个封闭类,前面用sealed,可以有任意多个字对象,封闭类的值只能是这些字对象,使用封闭类的好处,主要是与when表达式配合,不需要再使用else形式

sealed class Icon ()
class Small() : Icon()
class Big() : Icon()

fun eval(icon: Icon) {
        when (icon) {
            is Small -> {
            }
            is Big -> {
            }
        }
    }

var big = Big()
        eval(big)

3.  泛型

3.1 泛型基础

  所谓的泛型,就是指在定义数据结构时,只指定类型的占位符,等到使用该数据结构时在指定具体的数据类型

class Box<T>(t :T){
    var value = t
}

var box = Box<Int>(1)
Log.i("tag", ";;;;;;" + box.value);
3.2 类型变异

  Kotlin泛型并没有提供通配符,取而代之的是out和in的关键字(1)用out声明的泛型占位符只能用在获取泛型类型值的地方(2)用in声明的泛型只能在设置泛型类型值的地方

(1). 使用out关键字

abstract class Source< out T> {
   abstract fun NextT(): T
}

fun demo(strs: Source<String>) {
//编译通过,因为T是一个out类型参数
    val ni: Source<Any> = strs
    
}

(1).使用in关键字

abstract class Comparable<in T>{
    abstract fun comparaTo(other:T)
}

fun demo (x:Comparable<Number>){
//1.0时Double类型,Double时Number的子类型
    x.comparaTo(1.0)
    val y: Comparable<Double> = x
}
3.3 泛型函数
 fun <T> single(item :T) :T{
        return item
    }

var single = single(1)
 Log.i("tag", ";;;;;;" + single);
3.4 泛型约束

  最常见的约束是上界(upper bound),与Java的extends关键字相同,如果没有指定,默认使用的上界类型Any?,在定义泛型参数的尖括号内,只允许定义唯一一个上界,要是多个就的使用where

fun <T :Parent> convert(item :T){
}

fun<T>clone (list:List<T>,there:T):List<T> where T :Comparable,T:Cloneable{
//.....
}

总结

  通过本章节的学习,了解到了枚举类,数据类,封闭类,泛型,而且学到了非常方便的一个扩展的实用语法,可以很方便的为原生Api以及其他类扩充方法,比较灵活方便,也希望此篇幅的知识对你有稍许的帮助

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • 前言 人生苦多,快来 Kotlin ,快速学习Kotlin! 什么是Kotlin? Kotlin 是种静态类型编程...
    任半生嚣狂阅读 26,168评论 9 118
  • 面向对象编程(OOP) 在前面的章节中,我们学习了Kotlin的语言基础知识、类型系统、集合类以及泛型相关的知识。...
    Tenderness4阅读 4,425评论 1 6
  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 2,739评论 2 9
  • 夜静满天星,酒阑人未醒。 出神偏不觉,入梦似曾经。 拂影月千户,落花香半庭。 不知何处鸟,侵晓隔窗听。
    雪窗_武立之阅读 771评论 0 8
  • 早起,于朋友圏发现一个很有意思的公众号“早晚签到”。 又发现一早己下载却未常用的App即正在使用的“简书”...
    简单爱780324阅读 193评论 1 1