内容简介:通过上一篇的Kotlin介绍了一些基本的变量,方法,函数,类等的基本讲解,接下来,让我们更近一步的学习,深入一点的知识Kotlin的枚举类和Java的非常相似,具有类的特性,一般会将可枚举的同类型一组值作为枚举类定义,由于每一枚举都是个对象,可能在性能上还是不推荐用,Android中已经用注解慢慢取代了,这种枚举的使用在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以及其他类扩充方法,比较灵活方便,也希望此篇幅的知识对你有稍许的帮助
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 每秒解析千兆字节的 JSON 解析器开源,秒杀一大波解析器!
- 注册中心 Eureka 源码解析 —— EndPoint 与 解析器
- 新一代Json解析库Moshi源码解析
- mybatis源码配置文件解析之三:解析typeAliases标签
- MySQL内核源码解读-SQL解析之解析器浅析
- Laravel 核心——IoC 服务容器源码解析(服务器解析)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
深入理解 Flask
[美]Jack Stouffer / 苏丹 / 电子工业出版社 / 2016-7-1 / 79.00
Flask 是一种具有平缓学习曲线和庞大社区支持的微框架,利用它可以构建大规模的web应用。学习上手Flask非常轻松,但要深入理解却并不容易。 本书从一个简单的Flask应用开始,通过解决若干实战中的问题,对一系列进阶的话题进行了探讨。书中使用MVC(模型-视图-控制器)架构对示例应用进行了转化重构,以演示如何正确地组织应用代码结构。有了可扩展性强的应用结构之后,接下来的章节使用Flask......一起来看看 《深入理解 Flask》 这本书的介绍吧!