Kontlin笔记

var和val

可以理解为var声明变量,val声明常量。var是可读可修改,val只可读不可修改。
init{}类初始化块,相当于java中的静态代码块,在类被加载的时候就会执行。

空值
  • kotlin 中定义方法时,默认接收的是 非 null 参数。
  • 如果定义某个方法可以接收 null参数,则在声明方法参数时在参数后面加上?
fun test(str1:String?){    //String 后面的 ? 就表示该方法可以接收 null 作为参数
    //DO STH 
}

When表达式,类似于java中的switch:

when(变量){
    分支A -> 表达式
    else -> 表达式
}

带返回值的when表达式:

var result=when(变量){
    分支A -> 表达式(要有返回值,最终将值赋给result)
    else -> 表达式(要有返回值,最终将值赋给result)
}
for循环遍历list
 /**
     * for循环遍历list
     */
    fun forFunction() {
        val list = listOf("狗狗", "猫猫", "猪猪", "鹿鹿")
        for ((a, b) in list.withIndex()) {
            println(message = "TAG:$TAG  索引a:$a    值b:$b")
        }
    }
Map

声明格式:

var map=TreeMap<键类型,值类型>()
map[key]=value
Loop和Range
var nums1=1..100  //表示我们声明了一个闭区间数组,其中包含的数值为 1-100。 .. 表示闭区间
var nums2=1 util 100 //前闭后开区间,取值 1-99. util 表示前闭后开区间

示例:

 /**
     * for循环遍历list
     */
    fun forFunction() {
        val list = listOf("狗狗", "猫猫", "猪猪", "鹿鹿")
        println(message = "TAG$TAG ===========   索引     值")
        for ((a, b) in list.withIndex()) {
            println(message = "TAG:$TAG  索引a:$a    值b:$b")
        }
        //list内容反转
        list.reversed()
        println(message = "TAG$TAG ===========  list  反转     值")
        for (s in list) {
            println(message = "TAG$TAG  value:$s")
        }

        var l = 1..10
        var m = 1 until 10
        println(message = "TAG$TAG ===========    闭区间     值")
        for (i in l) {
            println(message = TAG + i)
        }
        println(message = "TAG$TAG ===========    前闭后开 unit     值")
        for (i in m) {
            println(message = TAG + i)
        }
        /**
         * 设置步长
         */
        println(message = "TAG$TAG ===========    步长     值")
        for (i in l step 2) {
            println(message = TAG + i)
        }
        //数据反转
        println(message = "TAG$TAG ===========   数据 反转     值")
        val reversed = l.reversed()
        for (i in reversed) {
            println(message = TAG + i)
        }
    }
函数和函数表达式
  • 函数的简化
//原函数:
fun sum(a:Int , b:Int):Int{
    return a+b
}

//简化后
fun sum(a:Int , b:Int):Int=a+b
使用var声明函数
 /**
     * 使用var声明函数
     * 函数表达式一
     */
    var i = { x: Int, y: Int -> x + y }

    /**
     * 函数表达式二
     */
    var j: (Int, Int) -> Int = { x, y -> x + y }
  
    //调用
    val i1 = i(2, 3)
    println(message = "TAG$TAG   函数i的调用结果:$i1")
    val j1 = j(4, 3)
    println(message = "TAG$TAG   函数j的调用结果:$j1")
默认参数和具名参数
  • 具有默认参数值的函数声明
val Pi=3.1415926
fun 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 声明我们传入了半径值
字符串和数字的转换

var a="13"
a.toInt() //字符串转换为Int
var b=13
b.toString() //Int转换为字符串

根据用户输入的数字动态计算
fun main(array:ArrayList<String>){
    println(“请输入第一个数值”)
    var a=readLine()    //读取键盘输入的字符串内容,并赋值给a 
    println(“请输入第二个数值”)
    var b=readLine()

    var num1=a!!.toInt()  //readLine()得到的可能是null,所以此处通过 !! 断言输入不为null
    var num2=b!!.toInt() 

    println("${num1}+${num2}=${num1+num2}")
}
异常处理
try{
    //可能会出错的代码块
}catch(e:Excepiton){
    //出错之后的处理逻辑
}
利用递归实现 阶乘函数
fun fact(a:Int):Int{
    if(a==1){
        return 1
    }else{
        return a*fact(a-1) //函数内调用函数本身就成为了递归
    }
}
尾递归优化
  • 尾递归的参详http://www.ruanyifeng.com/blog/2015/04/tail-call.html
    递归本质上是一种循环操作。纯粹的函数式编程语言没有循环操作命令,所有的循环都用递归实现,这就是为什么尾递归对这些语言极其重要,循环可以用递归代替,而一旦使用递归,就最好使用尾递归。
  • kotlin中尾递归关键字 tailrec
为什么需要尾递归优化

递归非常耗费内存,因为需要同时保存成千上百个调用记录,很容易发生"栈溢出"错误(stack overflow)。但 对于尾递归来说,由于只存在一个调用记录,所以永远不会发生"栈溢出"错误。
示例:

    /**
     * tailrec 是尾递归函数的关键字
     * 尾递归函数是指,在该函数的最后一步操作中依旧是调用函数本身
     * 为了实现尾递归,我们定义了该方法接收两个参数:num 是我们传入的需要计算累加值得的变量,total用来接收最终的返回值
     */
    tailrec fun accumulation(num: Int, total: Int): Int {
        return if (num == 1) {
            total
        } else {
            //此时,该调用的含义是:先计算 total=num+total,然后计算 num=num-1
            accumulation(num - 1, num + total)
        }
    }
面向对象入门——定义一个类并构建对象
//定义一个类,包含两个成员变量 height和width
class 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类中成员变量
}
静态属性和动态行为/方法——为类定义成员方法
//定义一个类,包含两个成员变量 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类中成员变量

}
面向对象

案例:

/**
 * 定义成员变量和成员方法
 */
class WashMachine(brand: String, size: Int) {

    var isDoorOpen = false
    var curMode = 0

    fun openDoor() {
        println("Wash     打开洗衣机的门    ")
        isDoorOpen = true
    }

    fun closeDoor() {
        println("Wash    关闭洗衣机的门    ")
        isDoorOpen = false
    }

    /**
     * 设置洗衣机的模式
     */
    fun setMode(mode: Int) {
        curMode = mode
        when (mode) {
            0 -> println("Wash  慢速模式")
            1 -> println("Wash   标准模式")
            2 -> println("Wash   快速模式")
            else -> println("Wash   初始状态")
        }
    }

    fun start() {
        if (isDoorOpen) {
            println("Wash   洗衣机的门还没有关闭,请先关闭洗衣机的门")
        } else {
            when (curMode) {
                0 -> {
                    println("Wash  现在是慢速模式,发动机转速慢")
                    println("Wash   开始洗衣服")
                }
                1 -> {
                    println("Wash   现在是标准模式,发动机正常运行")
                    println("Wash   开始洗衣服")
                }
                2 -> {
                    println("Wash   现在是快速模式,发动机快速运行")
                    println("Wash   开始洗衣服")
                }
                else -> println("Wash   你还没有设置洗衣机的模式")
            }
        }
    }
}

调用:

       val washMachine = WashMachine("小天鹅", 20)
        washMachine.setMode(2)
        washMachine.openDoor()
        washMachine.closeDoor()
        washMachine.start()
面向对象——继承
  • 一个对象直接使用另一个对象的属性或方法 —— 同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("儿子不喜欢看书,但是喜欢唱歌")
    }
}
抽象类及其实现
  • 抽象的关键字 abstract —— 同Java
  • 抽象类和方法不需要用 open 声明可以被继承/实现
    抽象类:
abstract class Human (var name: String){      //定义抽象类,使用 abstract 修饰。包含成员变量name
    abstract fun eat()      //定义抽象方法, 使用 abstract 修饰
}

实现:

class Man(name: String) : Human(name) {    //继承自Human抽象类
    override fun eat() {    //必须重写抽象方法
        println("${name}是男人,是家中劳力,所以吃的多")
    }
}
多态
  • 同种功能,不同的表现形式 即为 多态
    抽象类:
//定义抽象类,使用 abstract 修饰。包含成员变量name
abstract class Human(var name: String) {      
    //定义抽象方法, 使用 abstract 修饰
    abstract fun eat()      
   //定义抽象方法
    abstract fun pee() 
}

子类Man:

class Man(name: String) : Human(name) {
    override fun pee() {
        println("${name}是男人,是站着尿尿的")
    }

    override fun eat() {
        println("${name}是男人,是家中劳力,所以吃的多")
    }
}

子类Woman:

class Woman(name: String) : Human(name) {
    override fun eat() {
        println("${name}是女人,饭量比较小")
    }

    override fun pee() {
        println("${name}是女人,是蹲着尿尿的")
    }
}

调用示例:

fun main(args: Array<String>) {
    var man=Man("张三")
    var woman=Woman("小花")

    var list= listOf<Human>(man,woman)    //定义集合
    for (human in list){    //遍历集合
        human.pee()
    }
}
接口及其实现
  • 接口--数据有进有出的交互方式、
  • 接口关键字: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}是男人,是家中劳力,所以吃的多")
    }
}

太监不能实现IMan接口:

class TaiJian(name: String) : Human(name) {  //太监属于人,但是太监没有小弟弟,所以不能实现 IMan接口
    override fun eat() {
        println("太监也能吃饭")
    }

    override fun pee() {
        println("太监也会尿尿")
    }
}
代理和委托
  • 委托,把自己不干的事情交给别人做
  • 代理,做别人委托的事情
  • 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()    //小头爸爸已经将洗碗的操作委托为小头儿子了,所以,此处本质是调用的小头儿子的洗碗操作
}
单例模式
  • 单例关键字: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()    //小头爸爸已经将洗碗的操作委托为小头儿子了,但因为重写了洗完事件,所以,本子是调用的父亲的洗完事件,父亲的洗完事件中有一部分是自己做的,另一部分是儿子做的
}
枚举--enum

示例代码:

enum class Week {   //枚举关键字 enum 
    星期一, 星期二, 星期三, 星期四, 星期五, 星期六, 星期天
}

fun main(args: Array<String>) {
    println(Week.星期一)
    println("${Week.星期一}在Week中的索引是${Week.星期一.ordinal}")
}
结果.png
印章类/密封类 (Sealed Class)
印章类/密封类 (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)
    }
}
运行结果.png

https://www.jianshu.com/p/35f0c16242e4

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

推荐阅读更多精彩内容

  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 2,640评论 2 9
  • 对象的创建与销毁 Item 1: 使用static工厂方法,而不是构造函数创建对象:仅仅是创建对象的方法,并非Fa...
    孙小磊阅读 1,878评论 0 3
  • 文章内容主要是基于传智播客《kotlin从零基础到进阶》的视频做的笔记。标题中的 V 是Video的缩写,V4 ...
    CnPeng阅读 20,650评论 11 23
  • 面向对象主要针对面向过程。 面向过程的基本单元是函数。 什么是对象:EVERYTHING IS OBJECT(万物...
    sinpi阅读 1,023评论 0 4
  • 《Effective Java》笔记(上) 对象的创建与销毁 Item 1: 使用static工厂方法,而不是构造...
    OCNYang阅读 2,546评论 2 17