Kotlin学习笔记---持续更新中
1.程序入口
fun main(args:Array<String>){ println("hello world");}
fun:函数的声明,固定写法
main:程序的入口
args:接受的参数,数据类型字符串
2.变量和输出
-
变量的声明
var name="张三" //变量声明关键词var,语句末尾不需要分号
-
数据类型
类型 范围 Byte 整数-128~127 Short 整数-32768~32767 Int 整数-2147483648~2147483647 Long 整数-9223372036854775807~9223372036854775806 Float 小数,小数点可以精确到6位 Double 小数,小数点可以精确到15-16位 String 字符串,用双引号引起来的字符串都可以存 3.类型推断和显示类型声明
-
类型推断
-
在声明一个变量时,我们可以不需要显示声明数据类型,kotlin会根据你为变量赋的值动态地推导出其类型
-
当一个变量被赋予了某个类型的数值之后,不能再赋给他其他类型的数值,否则,会报类型错误
fun main(args:Array<String>){ var a=10 //声明变量a , 将int类型的10 赋值给a, a 将只能接受int型数据 a=15 //a="字符串" //将字符串类型的数据赋值给int型的a ,报错!! var s="字符串"}
-
-
显示类型声明
格式:
var变量名:变量类型=值
var a:Int=10
-
变量声明的注意事项
- 如果声明变量时就赋初值,可以不写类型,此时,类型推导将生效
- 如果声明变量时没有赋初值,则必须写明类型,否则会报错。格式:
var a:Int
-
常量的声明
关键字:val
格式:
val 常量名:常量类型=常量值
-
3.变量的取值范围
获取某种类型数据的最大最小值
fun main(args:Array<String>){ val minByte:Byte=Byte.MIN_VALUE val maxByte:Byte=Byte.MAX_VALUE val a:Int=0b0011 //将二进制的0b0011 转换为10进制,并复制给a }
- Byte、Int、Long可以通过上述方式获取最大最小值
- String没有最大最小值,所以没有上述方法
4.Kotlin函数入门
- main() 程序入口
- println() 打印
函数声明基本格式:fun 函数名(参数:参数类型){函数体}
5.字符串模板
- “”,被两个双引号包裹的内容是普通字符串,支持转义符
- “”" “”",被一对三引号包裹的内容是原样字符串,不支持转义字符,其中的内容被定义成什么样,输出的时候就是什么样
- 字符串模板格式:${占位字符串}
6.字符串比较
- 可以使用 == 比较字符串
- 也可以使用equals(,)方法比较字符串,该方法第二个参数表示是否忽略大小写,true–忽略,false–不忽略
- equals(,)中第二个参数为true时,效果等价于Java中的equalsIgnoreCase()
7.空值处理
- 以null表示空值
- kotlin中定义方法时,默认接收的是非null参数
- 如果定义某个方法可以接收null参数,则在声明方法参数时在参数后面加上**?**
8.When表达式
类似于Java中的switch,基本使用格式:
when(变量){ 分支A -> 表达式 else -> 表达式}
带有返回值的When表达式
var result=when(变量){ 分支A -> 表达式(要有返回值,最终将值赋给result) else -> 表达式(要有返回值,最终将值赋给result)}
9.Loop和Range
-
声明一个区间数组
var nums1=1..100 //表示我们声明了一个闭区间数组,其中包含的数值为 1-100。 .. 表示闭区间var nums2=1 util 100 //前闭后开区间,取值 1-99. util 表示前闭后开区间
-
for基本循环格式
for(变量 in 数组或字符串){ //DO STH }
-
带有步进的for循环
for (变量 in 数组 step 步进数量){ //所谓步进,就是递增幅度。默认步进为1 //DO STH }
-
数组.reversed() //数组内容反转
-
数组.count() //获取数组的容量,等价于Java中的数组.length
10.List和Map
-
List
-
List的基本声明格式:
var list1=listOf(元素1,元素2,元素3) //声明List时主要是通过 listOf()实现
-
使用for循环同时遍历索引和索引对应的数值
for((index,value) in list.withIndex()){ //重点是 withIndex() 方法,index 接收索引,value 接收对应的值 //DO STH }
-
-
Map(词典)
-
基本声明格式
var map=TreeMap<键类型,值类型>()map[key]=value
-
示例代码
var map=TreeMap<String,String>() //声明 mapmap["好"]=goodmap["学习"]=study //添加键值对元素println(map["好"]) //取值并打印
-
11.函数和函数表达式
-
函数的简化
//原函数:fun sum(a:Int , b:Int):Int{ return a+b}//简化后fun sum(a:Int , b:Int):Int=a+b
-
使用var声明函数–函数表达式1
kotlin 中除了使用基本的 fun 关键字声明函数外,还可以使用 var 声明。示例如下:
var i={x:Int , y:Int -> x+y} //声明函数i,接收两个Int类型参数 x、y,返回 x+y 的值i(3,5) //调用使用 var 声明的函数 i
-
使用var声明函数–函数表达式2
var j:(Int,Int)->Int={x,y -> x+y} //声明函数j,它接收的参数是两个Int, 返回一个Int,对应的表达式是 {x,y->x+y}j(4,4) //调用函数
12.默认参数和具名参数
-
具有默认参数值的函数声明
val Pi=3.1415926fun getRoundArea(PI:Float=Pi , radius:Float):Float{ //为变量PI赋予了默认值 Pi,这样,调用该方法时可以不再传递PI。但,如果我们想传入的值和默认值不一致时还是需要传入的 return PI*radius*radius}
-
调用带有默认参数值的函数
var a=getRoundArea(3.14f,5.0f) //因为我们相传入的PI和默认值不一致,所以,需要将3.14f传入
-
具名参数的使用
所谓具名参数,就是调用某个方法时指明传入的参数是给哪个变量的
var a=getRoundArea(radius=5.0f) //我们需要的PI值与默认值一致,此时不需要再传入PI值。只需要通过 radius=5.0f 声明我们传入了半径值
13.字符串和数字的转换
var a="13"a.toInt() //字符串转换为Intvar b=13b.toString() //Int转换为字符串
14.异常处理–同Java
try{ //可能会出错的代码块}catch(e:Excepiton){ //出错之后的处理逻辑}
15.递归
-
利用递归实现阶乘函数
fun fact(a:Int):Int{ if(a==1){ return 1 }else{ return a*fact(a-1) //函数内调用函数本身就成为了递归 }}
-
BigInteger
在上面的方法中,我们用Int来接收阶乘的值,但如果超出了Int的范围,就会返回0.所以这时候就需要用到BitInteger。BitInteger用来表示一个超大值。
import java.math.BigIntegerfun main(array: Array<String>) { val num = BigInteger("50") //声明BigInteger常量时传入一个字符串类型的数值 println(fact(num))}fun fact(num: BigInteger): BigInteger { return if (num == BigInteger.ONE) { BigInteger.ONE } else { num * fact(num - BigInteger.ONE) }}
16.尾递归优化
-
什么是尾递归
- 尾递归:是指某个函数的最后一步依旧是调用自身
- kotlin中尾递归关键字tailrec
-
为什么需要尾递归优化
递归非常耗费内存,因为需要同时保存成千上百个调用记录,很容易发生“栈溢出”错误(stack overflow)。但对于尾递归来说,由于只存在一个调用记录,所以永远不会发生栈溢出错误。
-
使用尾递归实现累加
fun main(args: Array<String>) { println(accumulation(5, 1))}/** * tailrec 是尾递归函数的关键字 * 尾递归函数是指,在该函数的最后一步操作中依旧是调用函数本身 * 为了实现尾递归,我们定义了该方法接收两个参数:num 是我们传入的需要计算累加值得的变量,total用来接收最终的返回值 */tailrec fun accumulation(num: Int, total: Int): Int { return if (num == 1) { total } else { accumulation(num - 1, num + total) //此时,该调用的含义是:先计算 total=num+total,然后计算 num=num-1 }}
17.面向对象入门-定义一个类并构建对象
//定义一个类,包含两个成员变量 height和widthclass Rect(var height:Int,var width:Int)fun main(args: Array<String>) { var rect=Rect(5,10) //构建Rect对象,不需要new println("矩形的宽${rect.width}高${rect.height}") //引用Rect类中成员变量}
18.静态属性和动态行为/方法-为类定义成员方法
//定义一个类,包含两个成员变量 height和width.并定义一个成员方法class Rect(var height: Int, var width: Int) { fun getArea(a: Int, b: Int): Int = a * b}fun main(args: Array<String>) { var rect = Rect(5, 10) //构建Rect对象,不需要new println("矩形的宽${rect.width}高${rect.height}") //引用Rect类中成员变量 println("矩形的面积是${rect.getArea(rect.width, rect.height)}") //引用Rect类中成员变量}
19.面向对象-继承
- 一个对象直接使用另一个对象的属性或方法-同Java
- 被继承的父类必须用open修饰,表示允许其他类继承该类
- 父类中的方法如果允许子类重写,也需要用open修饰
- 重写父类方法时需要用override修饰重写后的方法
- 继承的格式:
class 子类:父类()
父类:
open class Father { //用 open 修饰,允许被继承 var character = "性格内向" open fun action() { //用open修饰,允许被重写 println("喜欢读书") }}
子类:
class Son : Father() { //继承。 Son 继承自 Father override fun action() { //重写父类方法 //super.action() println("儿子的性格是$character") println("儿子不喜欢看书,但是喜欢唱歌") }}
20.抽象类及其实现
- 抽象类的关键字:abstract–同Java
- 抽象类和方法不需要用open声明可以被继承/实现
抽象类Human:
abstract class Human (var name: String){ //定义抽象类,使用 abstract 修饰。包含成员变量name abstract fun eat() //定义抽象方法, 使用 abstract 修饰}
抽象类的子类Man:
class Man(name: String) : Human(name) { //继承自Human抽象类 override fun eat() { //必须重写抽象方法 println("${name}是男人,是家中劳力,所以吃的多") }}
调用子类:
fun main(args: Array<String>) { var man=Man("张三") man.eat()}
21.接口及其实现
- 接口–数据有进有出的交互方式
- 接口关键字–interface,同Java
- 接口是事物的能力(代表某种事物的特性),抽象类是事物的本质(代表的是一类事物的共性)
- 子类实现接口时,接口名后面不需要()
定义接口IMan
interface IMan { //定义一个男人的接口 fun xiaodidi()}
Man类实现IMan接口
class Man(name: String) : Human(name) ,IMan{ //男人属于人,所以继承Human;男人有小弟弟,所以实现 IMan接口 override fun xiaodidi() { println("这是重写IMan接口中的方法——男人有小弟弟") } override fun pee() { println("${name}是男人,是站着尿尿的") } override fun eat() { println("${name}是男人,是家中劳力,所以吃的多") }}
22.代理和委托–大头儿子和小头爸爸的洗碗案例
- 委托,把自己不干的事情交给别人做
- 代理,做别人委托的事情
- kotlin中接口代理关键字:by
-
场景说明
围裙妈妈只负责做饭,不负责洗碗小头爸爸洗一次碗可以赚到10元大头儿子洗一次碗可以赚到1元小头爸爸承揽了洗碗的活,最终交给大头儿子做,中间赚了9元差价
-
代码实现–完全委托
-
定义洗碗的接口
interface IWashBow { //定义一个洗碗接口,包含一个洗碗方法 fun washBow()}
-
大头儿子实现接口
class BigHeadSon:IWashBow { //被实现的接口后面不需要加() override fun washBow() { println("我是大头儿子,每次洗碗赚1元钱") }}
-
小头爸爸实现接口并委托时间给小头儿子
class SmallHeadFather:IWashBow by BigHeadSon(){ //委托关键字 by;被委托方(即代理方)如果不是单例类,则后面需要跟()}
fun main(args: Array<String>) { var father=SmallHeadFather() father.washBow() //小头爸爸已经将洗碗的操作委托为小头儿子了,所以,此处本质是调用的小头儿子的洗碗操作}
-
23.单例模式
-
单例关键字:object
我们在定义一个类时,使用object替换class来修饰这个类,就表示这是一个单例类
-
单例类作为代理人时,不需要()
-
场景说明
小头爸爸为了增进父子感情,想和小头儿子一起洗碗
-
代码实现
-
小头爸爸重写接口方法,未使用单例时的错误写法
class SmallHeadFather:IWashBow by BigHeadSon(){ override fun washBow() { println("我是小头爸爸,我把洗碗事件委托给了大头儿子") BigHeadSon().washBow() //委托方重写了事件之后,需要手动调用代理方的方法。但是,此处又通过()构建了一个小头儿子对象,已经不再是我们初始委托的那个大头儿子了。所以,此处是有问题的。 println("我是小头爸爸,大头儿子洗完碗之后,我赚了9元") }}
-
使用单例后的正确写法
大头儿子单例类:
object BigHeadSon:IWashBow { //单例关键字object,声明为单例类之后会立即在内存中创建单例对象,并一直存在 override fun washBow() { println("我是大头儿子,每次洗碗赚1元钱") }}
小头爸爸委托事件给单例的大头儿子:
class SmallHeadFather:IWashBow by BigHeadSon{ //被委托方(即代理方)是单例类,不需要通过()构建对象 override fun washBow() { println("我是小头爸爸,虽然我把洗碗事件委托给了小头儿子,但是我要和他一起洗碗") BigHeadSon.washBow() //委托方重写了事件之后,需要手动调用代理方的方法。由于 BigHeadSon是单例的,所以,这还是我们之前委托的那个儿子 println("我是小头爸爸,我和小头儿子洗完碗之后,我赚了9元") }}
-
外部调用
fun main(args: Array<String>) { var father=SmallHeadFather() father.washBow() //小头爸爸已经将洗碗的操作委托为小头儿子了,但因为重写了洗完事件,所以,本子是调用的父亲的洗完事件,父亲的洗完事件中有一部分是自己做的,另一部分是儿子做的}
-
24.枚举
枚举示例代码:
enum class Week { //枚举关键字 enum 星期一, 星期二, 星期三, 星期四, 星期五, 星期六, 星期天}fun main(args: Array<String>) { println(Week.星期一) println("${Week.星期一}在Week中的索引是${Week.星期一.ordinal}")}
25.印章类/密封类(Sealed Class)
-
印章类的特点
- 子类类型有限的类成为 印章类/密封类
- 印章类使用 sealed 作为修饰符
- 印章类本身没有构造方法
-
印章类与枚举的区别
- 都是有限的数据
- 枚举更注重具体的数据
- 印章类更注重数据的类型
-
示例代码
-
场景说明
假设你家有一头公驴、一头母驴、一头公马。那么,它们可能会生出一头小驴,也可能会生出一头小骡子。
-
代码示例
在上述场景中,由于他们能生出的儿子类型时固定的,所以,我们可以使用印章类来标识。
声明印章类
sealed class Son { //使用 sealed 声明 Son 为印章类/密封类 class SmallMule() : Son() //声明小骡子 SmallMule 为 Son的子类。 class SmallDonkey() : Son() //声明小驴子 SmallDonkey 为 Son的子类 fun sayHello(son: Son) { if (son is SmallMule) { //判断是不是XX的实例的关键字 is println("小骡子对大家说大家好") } else if (son is SmallDonkey) { println("小驴子对大家说大家好") } }}
调用印章类
fun main(args: Array<String>) { var mule = Son.SmallMule() var donkey = Son.SmallDonkey() var list = listOf<Son>(mule, donkey) for (son in list) { son.sayHello(son) }}
-
更多相关文章
- Android(安卓)ProGuard使用要点!
- Android(安卓)蓝牙对战五子棋项目实现(含人机对战功能)
- Android(安卓)recovery 下删除第一次启动后的痕迹
- Android(安卓)6.0 开始声明权限的变更
- java.lang.NullPointerException: Attempt to invoke virtual me
- Android(安卓)防止设备休眠
- android 系统搜索框的使用及获取输入
- android启动过程详解(二)——解析service
- Android(安卓)对集合对象排序(快排与实现接口排序)