Kotlin基础篇

数据类型

基本数据类型

Int、Long、Float、Double、Boolean、Char、String

基本数据类型转换:调用toInt()、toString()等带to的方法类型转换。

数组

申明:var arr:Array<Int> = arrayOf(1,2,3) 或者

var arr:IntArray= intArrayOf(1,2,3)

数组基本操作:size长度、get、set等方法

字符串:

常用方法:indexOf、subString、replace、spit(特定字符子串分割子串)

子串拼接:$变量、${变量运算}

特殊字符转义:${'***'},外层${''}为转义申明,内层***为要转义的子串

容器

kotlin三个基本容器:Set、List、Map,然后每类容器又分为只读和可变。

可变容器:MutableSet、MutableList、MutableMap,只有可变容器才可以对元素增删改操作。

初始化:以此类推

var list:List<String> = listOf("a","b")

var list:MutableList<String> = mutableListOf("a","b")

遍历

for-in循环

迭代器遍历

forEach遍历:

var desc = ""

goodsMutSet.forEach{"desc = ${desc}名称:${it}\n"}

控制语句

条件分支

简单分支:if/else

多路分支:when/else

类型判断:is

循环处理

遍历循环

for/in:

for(item in list)

for(i in list.indices)遍历list的下标

迭代:

条件循环

关键字:util、step、downTo

for(i in 11 util 66):左闭右开,值包括11、不包括66

for(i in 11..66 step 4):每次默认增加1,这里改为4

for(i in 50 downTo 7):默认递增,这里递减

上面这几个都不太好,一般用when或者do/when

跳出多重循环

continue:继续下个循环

break:跳出循环

在外层循环前加个名字outSide的标记

例如:outSide@ while(){},在内层循环里break@outSide会跳出外层循环

空安全

?(如何为空返回null)

?:(Elvis运算符,设置默认值,如果为空返回默认值)

!!(既然运算符,强行放弃非空判断)

等式判断

==,!=(结构相等)  基本数据类型判断的是值是否相等,凡事实现了equals函数的类,变量均可通过结构相等判断。

===,!==(引用相等):基本数据类型结构相等跟引用相等没区别,引用数据类型比较的是内存地址。

s和!s:判断变量是否属于某种类型

in和!in:判断数组中是否含有某个元素

函数运用

函数的基本应用

函数声明方式

输入参数的格式

输出参数的格式

输入参数的变化

默认参数:允许定义函数时直接指定输入函数的默认值

命名参数:如果不满意参数的默认值,也可在调用函数时输入新的值

可变参数:kotlin新增vararg关键字,其后面的参数是不固定的vararg args:String,kotlin会把可变参数当做一个数组。

几种特殊的函数

泛型函数
内联函数

因为类的成员函数依赖于类,只有泛型类(又称模板类) 才能拥有成员泛型函数,而普通类是不允许定义泛型函数的,否则编译器会直接报错。不过有个例外情况,如果参数类型都是继承自某种类型,那么允许在定义函数时指定从这个基类泛化开,凡是继承自该基类的子类,都可以作为输入参数进行函数调用,反之则无法调用函数。

例如fun <reified T : Number>

简化函数

可将函数当作一种特殊的变量,既然变量通过等号赋值,那么函数也允许使用等号对输出参数赋值。具体地说,如果一个函数的表达式比较简单,一两行代码就可以搞定,那么Kotlin允许使用等号代替大括号。

例如递归函数:fun factorial(n: Int) = if n else n*factorial(n-1)
4.3.4 尾递归函数
4.33小节的阶乘函数只是一个普通的递归函数,

尾递归函数

Kotlin体系还存在一种特殊的递归函数,名叫尾递归函数,它指的是函数末尾的返回值重复调用了自身函数。此时要在fun前面加上关键字tailrec,告诉编译器这是一个尾递归函数,则编译器会相应进行优化,从而提高程序性能。
比如求余弦不动点,即可通过尾递归函数来实现,下面是具体的实现代码例子:
//如果函数尾部递归调用自身,那么可加上关键字tailrec表示这是一个尾递归函数
//此时编译器会自动优化递归,即用循环方式代替递归,从而避免栈溢出的情况
//比如下面这个求余弦不动点的函数就是尾递归函数
tailrec fun findFixPoint(x: Double = 1.0): Double
= if (x == Math.cos(x)) x else findrixPoint(Math.cos(x))

高阶函数

既然可以将函数当成变量,那么也可以将函数作为另一个函数的入参,这种为高阶函数。

例如:fun <T> max(array : Array<T> , greater(T,T) -> Boolean) : T?{}

增强系统函数

扩展函数

使用Java开发时,虽然系统自带的类已经提供了许多方法,然而经常还是无法完全满足业务需求,此时开发者往往要写一个工具类 (比如字符串工具类StringUtil、日期工具类DateUil等) 来补充相关的处理功能,长此以往,工具类越来越多,也越来越难以管理。
基于以上情况,Kotlin推出了扩展函数的概念,扩展函数允许开发者给系统类补写新的方法,而无须另外编写额外的工具类。比如系统自带的数组Array提供了求最大值的max方法,也提供了进行排序的sort方法,可是并未提供交换数组元素的方法。于是我们打算给Array数组类增加新的交换方法,也就是添加一个扩展函数swap。与普通函数定义不司的是,要在swap函数名称前面加上前缀“Array<lnt>”,表示该函数扩展自系统类Array<In>。下面是用于交换数组元素的swap函数定义代码:

fun Array<Int>.swap(pos1:Int,pos2:Int){}

扩展高阶函数
日期时间函数
单利对象

Object类用来声明单例对象

类和对象

类的构造

类的简单定义

(1) Kotlin省略了关键字public,缘于它默认就是开放的。

(2) Kotlin用冒号“:”代替extends,也就是通过冒号表示继承关系

(3) Kotlin进行继承时,父类后面多了括号“()”。

创建实例时的初始化在 init{} 中

类的构造函数

Kotlin引入了主构造函数与二级构造函数的概念。 跟在类名后面的参数是主构造函数的入参,同时init方法是主构造函数的内部代码,当然了也可以不要主构造函数。至于二级构造函数,则可以在类内部直接书写完整的函数表达式。

(1)二级构造函数没有函数名称,只用关键字constructor表示这是一个构造函数。

(2) 二级构造函数需要调用主构造函数。“this(context, name)”,在Kotlin中以冒号开头补充到输入参数后面,这意味着二级构造函数实际上是从主构造函数派生而来的,也可看作二级构造函数的返回值是主构造函数。

由此看来,二级构造函数从属于主构造函数,如果使用二级构造函数声明该类的实例,系统就会先调用主构造函数的init代码,再调用二级构造函数的自身代码。

constructor(context : Context, name : String , age : Int) : this(context , name) {}

带默认参数的构造函数

如果想让java也能识别kotlin构造函数的默认参数,需要再类名后加关键字@JvmOverLoads constructor

例如:class AnimalDefault @JvmOverLoads constructor(context :  Context , age : Int) {}

类的成员

成员属性

主构造函数中的参数变量前加var或者val,那么就会有同名的成员属性。

成员方法
伴生对象

kotlin中取消了关键字static,利用伴生对象实现静态成员的功能。

companion object WildAnimal{}

关键字companion表示伴随、object表示对象、WildAnimal表示伴生对象的名称

静态属性

类的继承

开放性修饰符

Kotlin默认每个类都不能被继承(相当于Java类被fnal修饰了) ,如果要让某个类成为基类,就需把该类开放出来,也就是添加关键字open作为修饰符。

public:对所有人开放。Konin 的类、函数、变量不加开放性修饰符的话,默认就是 oublic 类型
intemal:只对本模块内部开放,这是Konin 新增的关键字。对于 app开发来说,本模块是指本App
protected:只对自己和子类开放
private:只对自己开放,即私有

到底open跟这4个开放性修饰符是什么关系? 其实很简单,open不控制某个对象的访问权限,只决定该对象能否繁衍开来。只有带有open的类,才允许作为基类派生出子类来。

普通类继承
抽象类

也是abstract关键字,无法创建抽象类的实例。

因为抽象类不能直接使用,所有构造函数不必给默认参数赋值。

接口

关键字interface,接口不能定义构造函数。

与java不同的是,kotlin接口内部允许实现方法。

接口代理

Kotlin引入了接口代理的技术,即一个类先声明继承自某个接口,但并不直接实现该接口的方法,而是把已经实现该接口的代理类作为参数传给前面的类,相当于告诉前面的类:“该接口的方法我已经代替你实现了,你直接拿去用便是”。

//只有接口才能够使用关键字by进行代理操作

//如果by的对象是个类,编译器就会报错”Only interfaces can be delegated to"class

WildFowl(name:String, sex:Int=MALE behavior:Behavior) : Bird(name, sex) , Behavior by behavior {}

Behavior是一个接口,WildFowl实现Behavior接口,但是WildFowl不直接实现,而是把已经实现该接口的代理类作为参数传给前面的类。

几种特殊类

嵌套类

个类可以在单独的代码文件中定义,也可以在另一个类内部定义,后一种情况叫作嵌套类,即A类嵌套在B类之中。乍看过去,这个嵌套类的定义似乎与Java的嵌套类是一样的,但其实有所差别。Java的嵌套类允许访问外部类的成员,而Kotlin的嵌套类不允许访问外部类的成员。

调用嵌套类时,得在嵌套类的类名前添加外部类的类名

个人感觉跟静态内部类相似

内部类

既然Kotlin限制了嵌套类不能访问外部类的成员,那还有什么办法可以实现此功能呢?针对该问题,Kotlin另外增加了关键字inner表示内部,把inner加在嵌套类的class前面.于是嵌套类华丽地转变为了内部类,这个内部类比起嵌套类的好处是能够访问外部类的成员。所以,Kotlin的内部类就相当于Java的嵌套类,而Kotin的嵌套类则是加了访问限制的内部类。

枚举类

java中的枚举

enum Season ( SPRING,SUMMER,AUTUMN, WINTER)

上面的枚举类型定义代码看起来仿佛是一种新的数据类型,特别像枚举数组。可是枚举类型实际上是一种类,开发者在代码中创建enum类型时,Java编译器会自动生成一个对应的类,并且该类继承自java.ang.Enum。

Kotlin中的枚举,摒弃了“枚举类型”那种模糊不清的说法,转而采取“枚举类”这种正本清源的提法。具体到编码上,是将关键字enum作为class的修饰符,使之名正言顺地成为一种类一一枚举类。 按此思路将前面Java的枚举类型Season改写为Kotlin的枚举类,改写后的枚举类代码如下所示:

enum class SeasonType {

        SPRING,SUMMER,AUTUMN, WINTER

}

枚举类内部的枚举变量除了可以直接拿来赋值之外,还可以通过枚举值的几个属性获得对应的信息,例如ordinal属性用于获取该枚举值的序号,name属性用于获取该枚举值的名称。枚举变量本质上还是该类的一个实例,所以如果枚举类存在构造函数,枚举变量也必须调用对应的构造函数。这样做的好处是,每个枚举值不但携带唯一的名称,还可以拥有更加个性化的特征描述。 比如下面的枚举类SeasonName,其代码通过构造函数能够给枚举值赋予更加丰富的含义: enum class SeasonName (val seasonName: String) ( SPRING("春天") SUMMER("夏天"), AUTUMN(“秋天"), WINTER("冬天”) 下面的代码分别演示如何使用枚举类SeasonType和SeasonName:

enum class SeasonName (val seasonMame: String) (
        SPRING("春天")
        SUMMER("夏天”)
        AUPUMN(“秋天“),
        WINTER("冬天")

}

密封类

为解决枚举值判断的多余分支问题,Kotlin提出了“密封类”的概念,密封类就像是一种更加严格的枚举类,它内部有且仅有自身的实例对象,所以是一个有限的自身实例集合。定义密封类的时候,需要在该类的class前面加上关键字sealed作为标记。外部使用when语句判断密封类型值时便无须指定else分支了。

数据类

数据类说神秘也不神秘,它的类定义代码极其简单,只要开发者在class前面增加关键字“data”,并声明拥有完整输入参数的构造函数,即可无缝实现以下功能:

(1) 自动声明与构造函数入参同名的属性字段

(2)自动实现每个属性字段的get/set方法

(3)自动提供equals方法,用于比较两个数据对象是否相等。

(4)自动提供copy方法,允许完整复制某个数据对象,也可在复制后单独修改某几个字段的值。

(5) 自动提供toString方法,用于打印数据对象中保存的所有字段值。

 //数据类必须有主构造函数,且至少有一个输入参数

//并且要声明与输入参数同名的属性,即输入参数前面添加关键字va1或者var

//数据类不能是基类也不能是子类,不能是抽象类,也不能是内部类,更不能是密封类

data class Plant(var name:String, var stem:String, var leaf:String, varflower:String, var fruit:String, var seed:String) 

模版类

模版类就是java中的泛型类。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值