Kotlin从入门到热爱(一)

文章是在学习Kotlin时的学习总结笔记,如果觉得写的不好,请直接批评指出!
注:文档中部分内容摘自学习时的视频中ppt,仅供学习交流使用。

kotlin简介

Kotlin 是一个基于 JVM 的新的编程语言,由JetBrains开发。

静态强类型,与java100%兼容。

Kotlin可以编译成Java字节码,也可以编译成JavaScript,方便在没有JVM的设备上运行。

Kotlin已正式成为Android官方支持开发语言。

1. 为什么需要kotlin

空类型安全

Lambda表达式

扩展方式(扩展函数和扩展属性)

类型推导

胜任java能做的所有事,更简单

没有分号

2. 环境搭建

Intellij Idea或者Android studio等idea编辑器。

官网下载 IntelliJ IDEA 可执行文件:www.jetbrains.com/idea/

windows操作系统安装并激活 IntelliJ IDEA 可参考:blog.csdn.net/qq_35246620/article/details/61200815

官网下载 Android studio 可执行文件:developer.android.com/studio/index.html

Android Studio是基于IDEA开发的,但studio是一个纯粹的Android开发环境,并不支持诸如Groovy,scale。但Android Studio使用操作姿势与IntelliJ IDEA很相似。

3.如何说服管理层采用Kotlin

说服管理层采用kotlin.png

4. Hello World

下面我们编写我们第一个Kotlin程序,输出“Hello World!”

fun main(args: Array<String>) {
    println("Hello Horld!")
}

数据类型

对Kotlin有了一个基本了解,下面我们再了解一下Kotlin的数据类型吧

1、Boolean类型

在Kotlin当中,Boolean类型大多数情况相当于java中基本类型boolean,只有在必要的时候才会装箱成java中装箱类型Boolean。那我们到底选择哪一个呢,其实都交给编译器去处理了,我们不需要去担心。

val tbool:Boolean = true
val fbool:Boolean = false

2、Number类型

主要包括整型和浮点型。
Number类型.png

//整形
val num1:Int = 8  //十进制 8
val num2:Int = 0XFF  //十六进制 255
val num3:Int = 0b00000011  //二进制 3
val maxInt:Int = Int.MAX_VALUE  //最大整型值
val minInt:Int = Int.MIN_VALUE  //最小整型值

//长整形
val along:Long = 123432424342324
println(18L)  //整型强转长整形
Long.MAX_VALUE  //最大长整型值
Long.MIN_VALUE  //最小长整型值

//短整形
val aShort:Short = 12345
Short.MAX_VALUE  //最大短整型值
Short.MIN_VALUE  //最小整型值

//字节
val aByte:Byte = 127
Byte.MAX_VALUE  //Byte最大值 127
Byte.MIN_VALUE  //Byte最小值 -128

//单精度
val aFloat:Float = 2.0F  //在Kotlin中2.0默认表示双精度,所以需要加f强转 2.0
val another:Float = 1E3f  //10的3次方 1000.0
Float.MAX_VALUE  //最大单精度
Float.MIN_VALUE  //最小单精度,但MIN_VALUE是最小的正数(负数的最大值),非0,加上-号。所以可用 -Float.MAX_VALUE去表示

//双精度
val aDouble:Double = 3.0
val anotherD:Double = 2.34354
Double.MAX_VALUE   //最大双精度
Double.MIN_VALUE  // //最小双精度,与Float.MIN_VALUE类似,也是一个正数

NaN,“not a number”一个不是数的数,
例如:

println(0.0F/0.0F) //输出结果 NaN
prinln(0.0F/0.0F ==Float.NaN)  //输出结果 false

说明NaN的结果和其他NaN的结果不是相等的,比较起来没有意义,也不要去尝试。

3、Char类型

字符对应java的Character
占两个字节,标示一个16位的Unicode字符
字符用单引号 ’ 引起来,例如:‘a’, ‘6’, ‘\n’

val aChar:Char = 'a'
val bChar:Char = '中'
val cChar:Char = '\u000f'  //Unicode字符

转义字符.png

4、基本类型的转换

不可隐式转换

val anInt:Int = 5
val aLong:Long = anInt.toLong()  //  这样才可以转换
val aShort:Short = 12345
val aD:Double = aShort.toDouble()//  这样才可以转换

5、字符串

val string:String = "hello"  //声明一个字符串
val fromChars:String = String(charArrayOf('h','e','l','l','l','o'))  //字符数组
println(string == fromChars)   //== 比较值
println(string === fromChars)   //=== 引用

输出结果:分别是true和false。
所以“a==”比较的是内容是否相同,即类似java的equals,“a===b”比较对象是否相同
字符串模板特性

val arg1: Int = 0
val arg2: Int = 1
println("" + arg1 + " + " + arg2 + " = " + (arg1 + arg2))
println("$arg1 + $arg2 = ${arg1 + arg2}")

输出结果.png
**原始字符串 “”" **
原始字符串用三个"标示,内部字符串无法转义。

var rawStr:String = """\t\n\$666\t哈哈哈"""
println(rawStr.length)

"""原始字符,输出结果.png
字符串.length获取字符串长度
###5、类与对象
与java中概念基本相同,只不过写法不同。
Any相当于java中的Object

class 妹子(性格: String, 长相: String, 声音: String): 人(性格, 长相, 声音)
class 帅哥(性格: String, 长相: String, 声音: String): 人(性格, 长相, 声音)

open class 人(var 性格: String, var 长相: String, var 声音: String){
    init {
        println("new 了一个${this.javaClass.simpleName}, ta性格:$性格, 长相:$长相, 声音:$声音")
    }
}

fun main(args: Array<String>) {
    val 我喜欢的妹子: 妹子 = 妹子("温柔", "甜美", "动人")
    val 我膜拜的帅哥: 帅哥 = 帅哥("彪悍", "帅气", "浑厚")
    println(我喜欢的妹子 is 人)  //判断是属于某个类
}

6、空类型和智能类型转换

空类型.png

直接看实例及实例中注释:

    //?返回值可以为空
    fun getName(): String? {
        return null
    }

    fun getLenght() {
        // ?: 判断getName()如果为空,执行return
        var name: String = getName() ?: return
        var len = name.length
        // !! 不进行非空判断
        var len2 = getName()!!.length

        var value:String? = "Hello World"
        // !! 不进行非空判断
        println(value!!.length)

        //value 是String或!=null,后续可以不用在做null判断
        if(value is String)
            print(value)

        if(value!=null)
            print(value)
    }

智能类型转换1.png
智能类型转换1.png

        var parent:Parent = Child()
        if(parent is Child){
            //不像java还需要强转 ((Child)parent).getName()
            parent.getName()
        }

        //类型转换异常
        var child1:Child? = parent as Child
        // as? 如果转化失败返回null
        var child2:Child? = parent as? Child

        open class Parent
        class Child : Parent() {
            fun getName(): String {
                  return "name"
            }
        }

7、包

包.png

8、区间

一个数学上的概念,表示范围
ClosedRange的子类,InteRange最常用
基本写法:

0…100表示 [0,100]
0 until 100表示 [0,100)
(0…100).contains(i) 和 i in 0…100 均判断i是否在区间[0,100]中
示例:

var range: IntRange = 1..1024 //[0,1024]
var range_exclusive: IntRange = 1 until 1024 //[0,1024)

var range: IntRange = 1..1024 //[0,1024]
    var range_exclusive: IntRange = 1 until 1024 //[0,1024)
    print(range.contains(100))
    print(100 in range)
    print(range.isEmpty())
    for(i in range)
    {
        print("$i,")
    }

9、常量与变量(var,val)

Kotlin中有两个关键字定义变量,这两个关键字外形看着差别很小就只差了一个字母,但实际差别很大的。
var是一个可变变量,这是一个可以通过重新分配来更改为另一个值的变量。这种声明变量的方式和java中声明变量的方式一样。
val是一个只读变量,这种声明变量的方式相当于java中的final变量。一个val创建的时候必须初始化,因为以后不能被改变。
什么是常量?
val = value,值类型
类似Java的final
不能重复赋值
举例:

运行时常量:val x = getX()
编译期常量:const val x = 2 会提高执行效率

什么是变量?
var = variable
举例:

var x = “HelloWorld”//定义变量
x = “HiWorld”//再次赋值

类型推导
编译器可以推导量的类型

val string = “Hello” //推导出String类型
val int = 5 //Int类型
val x = getString() + 5//String类型

10、数组

先通过实例简单了解一下:

    var arrayOfInt: IntArray = intArrayOf(1, 2, 3, 4)
    var arrayOfChar: CharArray = charArrayOf('a', 'p', 'p', 'l', 'e')
    var arrayOfString: Array<String> = arrayOf("今天", "怎么", "不开心")
    for(i in arrayOfInt){
        print(i)
    }
    print(arrayOfChar.joinToString())//a,p,p,l,e
    print(arrayOfInt.slice(1..2))//[2,3]

1、基本写法:

val array:Array = arrayOf(…)

2、基本操作

print array[i] 输出第i个成员
array[i] = “Hello” 给第i个成员赋值
array.length 数组的长度

为了避免不必要的装箱和拆箱,基本类型的数组是定制的

JavaKotlin
int[]IntArray
short[]ShortArrary
long[]LongArrary
float[]FloatArrary
double[]DoubleArrary
char[]CharArrary

3、创建数组

(1)创建空数组,只读

val arrayEmpty = emptyArray<String>()

(2)创建指定长度的可空数组

val array1 = arrayOfNulls<Int>(5)
for (i in 0..4) {
    array1[i] = i
}

(3)创建指定长度数组

val array4 = Array(5, {0})

初始化长度为5,元素均为0的数组

val array5 : Array<String> = Array(5, {""})
for (i in 0..2) {
    array5[i] = i.toString()
}

初始化长度为5,元素均为""的数组,并为数组前3个元素赋值,“0”, “1”, “2”, “”, “”

(4)使用闭包创建数组

val array = Array(4, { i -> i * i })  //0,1,4,9,16

(5)使用Kotlin封装方法创建数组

val array1 = arrayOf(1, 2, 3, 4)
val array2 = intArrayOf(1, 2, 3, 4)

3、遍历数组

 var arr:IntArray = intArrayOf(1,2,3,4,5,6,7,8,9,10,11)
// 迭代器遍历数组1
val it = arr.iterator()
for (item in it.iterator()) {
    println(item)
}
// 迭代器遍历数组2
val it1 = arr.iterator()
it1.forEach {
    println(it)
}
// forEach遍历数组
arr.forEach ForEach@{
	if(it == "a") return@ForEach
    println(it)
}
for((index,value) in arr.withIndex()){
     print("$index -> $value,")
}

for(indexValue in arr.withIndex()){
     print("${indexValue.index} -> ${indexValue.value},")
}
// 等等...

11、函数

什么是函数?
以特定功能组织起来的代码块

fun函数名:[返回值类型]{[函数体]}
fun函数名 = [表达式] //返回值是Unit(相当于java中的void),可不写

匿名函数

fun([参数列表])…

举例:

val say = fun(name:String){ println(“Hello”) }
val say = fun(name:String) = println(“Hello”)

12、lambda表达式

实际上就是匿名函数
写法**{[参数列表]->[函数体,最后一行是返回值]}**
举例:

val sum = {a:Int,b:Int->a+b}
返回的是a+b的和

类型表示举例
1、()->Unit无参,返回值为Unit
2、(Int)->Int传入整型,返回一个整型
3、(String,(String)->String)->Boolean传入字符串、Lambda表达式,返回Boolan

Lambda表达式的调用
1、用()进行调用
2、等价于invoke()
举例

val sum = {a:Int,b:Int->a+b}
sum(2,3)
sum.invoke(2,3)

Lambda表达式的简化
1、如果函数调用时,最后一个是lambda表达式,在传参的时候可以将它移出去
2、函数参数只有一个lambda表达式,调用时小括号可省略
3、lambda表达式只有一个参数,不写也可以,名字默认为it
4、实参、返回值与形参一致的函数可以用方式作为实参传入

13、类成员(成员方法、成员变量)

属性
或者说成员变量,类范围内的变量
方法
或者说成员函数,类范围内的函数
函数和方法的区别
1、函数强调功能本身,不考虑从属
2、方法的称呼通常是丛类的角度出发
3、叫法不同
定义方法
写法与普通函数完全一致
定义属性
1、构造方法参数中var/val修饰的都是属性
2、类内部也可以定义属性

class Hello(val aField:Int,notAFlield:Int){
var anotherField:Float = 3f
}
aField 是属性
notAField 不是属性,只是普通构造方法的参数

属性的访问控制
属性可以定义getter/setter
举例:

var a: Int = 0
get() = field
set(value) {
field = value
}
val b:Float = 0f
//set(value){ field =value}
get() = field

val不可以set().png
属性初始化
1、属性的初始化尽量在构造方法中完成
2、无法在构造方法中初始化,尝试降级为局部变量
3、var用lateinit延迟初始化,val用lazy
4、可空类型谨慎用null直接初始化(不建议使用null初始化)

class LazyTest {
var a: Int = 0;
lateinit var str: String
lateinit var x1: X
val STR: String = “STR”
val x2: X by lazy {
print(“lazy X”)
X()
}
}

class X

fun main(args: Array) {
val e: LazyTest = LazyTest()
e.x2
}

14、基本运算符

1、任何类都可以定义或重载父类的基本运算符
2、通过运算符对应的具名函数来定义
3、对参数的个数要求,对参数和返回值类型不做要求
4、不能像Scala一样定义任意运算符

15、表达式(中缀表达式、分支表达式、when表达式等)

1、中缀表达式
只有一个参数,且用infix修饰的函数

fun main(args: Array<String>) {
    val b = Book();
    b on "哈哈"
}
class Book {
    infix fun on(str: String) {
        print("Book on $str")
    }
}

运行结果:Book on 哈哈

2、分支表达式
1)if…else

if(ab)…else if(ac)…else…

示例如下:
分支语句
2)表达式与完备性

val x = if(b<0) 0 else b
val x = if(b<0) 0 //错误,赋值时,分支必须完备

3、when表达式
1)加强版switch,支持任意类型,不需些break
2)支持纯表达式条件分支(类似if)
3)表达式与完备性
举例:

fun main(args: Array<String>) {
    val x = 5
    when (x) {
        is Int -> println("整型")
        in 0..10 -> println(" x in 0..10")
        in 0..100 -> println(" x in 0..100")

        5 -> println("x:$x 值是5")
    }

    val a = when{
        x in 0..10 ->100
        else ->0
    }
    print("a的值是$a")
}

结果:
when事例结果.png

16、循环语句(for循环、while循环、continue、break)

1)for循环
a.基本写法

for(element in elements)…

b.给任意类实现Iterator方法
运行机制简单举例:

class MyIterator(val iterator:Iterator<Int>){

    operator fun next():Int{
        return iterator.next()
    }

    operator fun hasNext():Boolean{
        return iterator.hasNext()
    }

}

class MyIntList{
    private val list = ArrayList<Int>()

    fun add(int:Int){
        list.add(int)
    }

    fun remove(int:Int){
        list.remove(int)
    }

    operator fun iterator():MyIterator{
        return MyIterator(list.iterator())
    }
}

fun main(args: Array<String>) {
    val list = MyIntList()
    list.add(1)
    list.add(2) 
    list.add(3)

    for (i in list){
        println(i)
    }
}

2)while循环
a. do…while(…)…
b. while(…)…
3)continue
跳过当前循环
4)break
终止循环
多层循环嵌套的终止结合标签使用

Outter@for(…){
Inner@while(i<0){if(…break@Outter)}
}
如果break后面没有@Outter,是把while给break了,会继续执行for循环,如果加了@Outter了,就是for循环给break了

17、异常捕获(try…catch、finally)

try…catch
1、catch分支匹配异常类型
2、表达式,可以用来赋值,与if…else、when类似
例如:

fun main(args: Array<String>) {

    val a = try {
        0 / 3
    } catch (e: Exception) {
        e.printStackTrace()
        println("出现异常")
        0
    } finally {
        println("执行finally")
    }
    println(a)
}

运行结果:

执行finally
3

finally
无论代码是否抛出异常都会执行

return try(x/y)catch(e:Exception){0}finally{…}
如果抛异常返回0,否则返回x/y,finally一定会执行,先执行finally再返回。

18、具名参数,变长参数、默认参数

1)具名参数
给函数的实参附上形参
举例:

fun sum(arg1:Int,arg2:Int) = arg1+arg2
sum(arg1=2,arg2=3)

2)变长参数
a.某个参数可以接收多个值
b.可以不为最后一个参数
c.如果传参时有歧义,需要使用具名参数

示例如下:
变长参数与具名参数
变长参数
Spread Opreator *
a.只支持展开的Array
b.只用于变长参数列表的实参
c.不能重载

3)默认参数
a.为函数参数指定默认值
b.可以为任意位置的参数指定默认值
c.传参时,如果有歧义,需要使用具名参数

19、练习

1)简单实现计算器

fun main(args: Array<String>) {

    while (ok()) {
        try {
            println("请输入,例如:3 + 4")
            val input = readLine() ?: break
            val split = input.trim().split(" ")
            if (split.size < 3) {
                throw IllegalArgumentException("参数个数不对")
            }
            val a = split[0].toDouble()
            val op = split[1]
            val b = split[2].toDouble()
            println("$a $op $b -> ${Opreator(op).apply(a, b)}")
        } catch (e: NumberFormatException) {
            println("您输入的数字有误")
        } catch (e:IllegalArgumentException) {
            println("参数有误")
        }catch (e:Exception){
            println("其他异常,${e.message}")
        }

        println("再来一发吗?[Y]")
        val cmd = readLine()
        if (cmd == null || cmd.toLowerCase() != "y") {
            break
        }
    }
    println("退出成功!")
}

fun ok(): Boolean {
    return true
}

21、面向对象-抽象类与接口

1)什么是接口
接口,直观理解就是一种约定
kotlin的接口与Objcet-C的Protocal比较类似
举例:

interface InputDevice{
fun input(event:Any)
}

2}接口
a.接口不能有状态
b.必须由类对其进行实现后使用
3)抽象类
a.实现了一部分协议的半成品
b.可以有状态,可以有方法实现
c.必须由子类继承后使用
4)抽象类和接口的共性
a.比较抽象,不能直接实例化
b.有需要子类(实现类)实现的方法
c.父类(接口)变量可以接受子类(实现类)的实例赋值
d.抽象类反映本质,接口体现能力
5)抽象类和接口的区别
a.抽象类有状态,接口没有状态
b.抽象类有方法实现,接口只能有无状态的默认实现
c.抽象类只能单继承,接口可以多实现

22、继承

1)父类需要open才可以被继承,抽象类不需要
2)父类方法、属性需要open才可以被复写
3)接口、接口方法、抽象类默认为open
4)复写父类(实现接口)的方法需要override关键字
5)class D:A(),B,C
6)继承类时实际上是调用了父类构造方法
7)类只能单继承,接口可以多实现
接口代理

class Leader(val dr:Drive,val pp:PPT)? by dr,P by pp

接口方法实现交给代理类实现
事例:

interface  D{
    fun drive()
}

interface P{
    fun write()
}
 class Drive:D{
   override fun drive(){
        println("开车")
    }
}

class PPT:P{
  override fun write(){
        println("写ppt...")
    }
}

//接口代理
class Leader(val dr:Drive,val pp:PPT):D by driver,P by write

fun main(args: Array<String>) {
    val lead = Leader(pp=PPT(),dr=Drive())
    //接口代理调用
    lead.drive()
    lead.write()
}

接口方法冲突
1)接口方法可以有默认实现
2)方法名、方法参数以及返回值相同,否则会有冲突
3)子类(实现类)必须复写冲突方法
4)super<[父类(接口)名]>.[方法名]([参数列表])
事例:

open class A {
    open fun x(): Int = 'A'.toInt()
}

interface B {
    fun x(): Int = 'B'.toInt()
}

interface C {
    fun x(): Int = 'C'.toInt()
}

class F(var y: Int) : B, C, A() {
    override fun x(): Int {
        return when {
            y > 0 -> super<A>.x()
            y < 0 -> super<B>.x()
            else -> super<C>.x()
        }
    }
}

fun main(args: Array<String>) {
    println(F(-1).x())//B
    println(F(0).x())//C
    println(F(1).x())//A
}

运行结果:66,67,65

23、类及其成员的可见性(private,protected,internal,public)

注:internal在和java兼容方面依旧存在问题,暂不建议使用
可见性对比.png

24、object

1)只有一个实例的类
2)不能自定义构造方法
3)可以实现接口、继承父类
4)本质上就是单例模式最基本的实现
注:如果不考虑懒加载等因素,Kotlin中写单例,使用的是object。

25、伴生对象与静态成员

针对使用静态方法的场景,请尽量考虑使用包级函数

Companion
1)每个类可以对应一个伴生对象
2)伴生对象的成员全局独一份
3)伴生对象的成员类似Java中的静态成员
4)静态成员考虑用包级函数、变量替代
5)JvmField和JvmStatic的使用
示例:
在这里插入图片描述
无论加不加**@JvmStatic@JvmField**在kotlin都可正常调用,而Java若想调用,则必须添加这两个注解。

class Latitude private constructor(val d:Double){
    companion object {
        @JvmStatic
        fun la(d: Double):Latitude{
            return Latitude(d)
        }
        @JvmStatic
        fun getD(latitude: Latitude):Latitude{
            return Latitude(latitude.d);
        }
        @JvmField
        val TAG:String = "TAG"
    }
}

kotlin中调用

fun main(args: Array<String>) {
var latitude = Latitude.la(6.66)
val latitude2 = Latitude.getD(latitude)
val tag = Latitude.TAG
}

java中调用

Latitude latitude = Latitude.la(3.234);
Latitude latitude2 = Latitude.getD(latitude);
String tag = Latitude.TAG;

26、方法重载与默认参数

1)方法重载
a.Overloads
b.名称相同、参数不同的方法
c.Jvm函数签名的概念:函数名、参数列表
d.跟返回值无关
2)默认参数
a.为函数参数设定一个默认值
b.可以为任意位置的参数设置默认值
c.函数调用产生混淆时用具名参数

方法重载转默认参数,下图示例:
在这里插入图片描述

3)方法重载和默认参数
a.二者的相关性以及**@JvmOverloads**(给java中调用kotin中的默认参数时使用)
事例:

class Overloads {
//    fun a(): Int {
//        return 0
//    }
   //  @JvmOverloads
    fun a(int: Int = 0): Int {
        return int
    }

    fun a(str: String): Int {
        return str.toInt()
    }
}

fun main(args: Array<String>) {
    val ovarLoads = Overloads()
    ovarLoads.a(1)
    ovarLoads.a("2")
//kotlin中调用 
    println(ovarLoads.a())
}

未加@JvmOverLoads时javad调用.png
加上@JvmOverLoads时java的调用.png

b.避免定义关系不大的重载
c.不好的设计

List.remove(Int)
List.remove(Object)

事例:
java中remove.png
kotlin中remove.png

27、扩展成员

为现有类添加方法属性

fun X.y():Z{…}

val X.m 注:扩展属性不能初始化,类似接口属性
Java调用扩展成员类似调用静态方法
事例:
二元运算符.png

fun main(args: Array<String>) {
    println("abc".times(6))
    println("a" * 6)
    println("a".a )
    println("b".b)
}
//扩展方法
operator fun String.times(num: Int): String {
    val sb = StringBuffer()
    if (num > 0) {
        for (i in 0 until num) {
            sb.append(this)
        }
    }
    return sb.toString()
}
//扩展属性
val String.a
    get() = 5
var String.b
    set(value){}
    get() = 6

运行结果:
运行结果.png

28、属性代理

1)定义方法

val/var : by

2)代理者需要实现相应的setValue/getValue方法
事例:

class Delegate {
    val x1 by lazy {
        "Hello X"
    }
    var x2 by X()
    var x3 by X()

}

class X {
    private var value: String? = null

    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        println("getValue---------$thisRef--------------------${property.name}")
        return value ?: ""
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("setValue------------$thisRef----------------${property.name}-----------$value")
        this.value = value
    }
}

fun main(args: Array<String>) {
    val delegate = Delegate()
    println(delegate.x1)
    println(delegate.x2)
    println(delegate.x3)
    delegate.x3 = "666666666666666666666"
    println(delegate.x3)
}

输出结果:
运行结果截图.png

29、数据类(allOpen,noArg插件,再见,javaBean)

1)data class默认实现了copy、toString、hashCode、equals等方法
2)componentN方法
3)allOpen和noArg插件

示例:
在这里插入图片描述
在这里插入图片描述

30、内部类(this@Outter,this@Inner)

内部类
a.定义在类内部的类
b.与类成员有相似的访问控制
c.默认是静态内部类,非静态用inner关键字
d.this@Outter,this@Inner的用法
示例:
内部类访问外部成员
在这里插入图片描述
匿名内部类
a.没有定义名字的内部类
b.类名编译时生成,类似Outter$1.class这样的类名
c.可继承父类、实现多个接口,与Java注意区别
示例:
在这里插入图片描述
kotlin中匿名内部类可以多实现
在这里插入图片描述

31、枚举(enum)

实例可数的类,注意枚举也是类
可以修改构造,添加成员
可以提升代码的表现力,也有一定的性能开销

32、密封类(sealed Class)

1)子类可数
kotlin版本<1.1,子类必须定义为封闭类的内部类
v1.1,子类只需要与密封类在同一文件中或者是它的内部类
示例:
在这里插入图片描述
2)与枚举类似却又不同
枚举是实例可数,密封类是子类可数;
示例:
在这里插入图片描述

高阶函数的基本概念

f(g(x))
传入或者返回函数的函数;
函数引用 ::println;
带有Receiver的引用

示例:
在这里插入图片描述

常见高阶函数

在这里插入图片描述
1. map
先看示例:

  var list = listOf<Int>(1, 2, 3, 4, 5, 6, 7)
    var newList = ArrayList<Int>()
    list.forEach {
        var newElement = it * 2 + 3
        newList.add(newElement)
    }

    //map
    var newList2 = list.map {
        it * 2 + 3
    }
    newList.forEach(::println)
    newList2.forEach(::println)
    /**
     * 等同:var newList3 = list.map{
     *      it.toDouble
     * }
     */
    var newList3 = list.map(Int::toDouble)//函数引用

    newList3.forEach(::println)

newList与newList2输出结果相同,而newList3数值是相同的,只不过转化成了double类型。

2. flatMap
先看示例:

  var list = listOf(
        1..30,
        2..10,
        100..120
   )

    var flatMapList = list.flatMap {
        it
    }

    /**
     * 等同于
     * 
     * list.flatMap {
     * it.map {
     * "NO.$it"
     * }
     * }
     */
    list.flatMap { intRange ->
        intRange.map { intElement ->
            "NO. $intElement"
        }
    }

3. reduce
示例:
在这里插入图片描述
4. fold和joinToString
fold充当有初始值的recude,其次还可以做一些变换,如字符串拼接,还有foldRight,foldIndex等;
joinToString,字符串拼接神器
示例:
在这里插入图片描述
**5. filter过滤 **
示例:
在这里插入图片描述
6. takeWhile
遇到第一个不符合条件的数据结束取数据,留下前面的作为一个新的集合返回;
示例:
在这里插入图片描述
7. let
示例:
在这里插入图片描述
8. apply
示例:
在这里插入图片描述
9. with
with和apply的区别
在这里插入图片描述
示例:
在这里插入图片描述
10. readText
示例:
在这里插入图片描述
11. readLines
把所有的行都读到;

12. use
示例:
在这里插入图片描述
相比with省了close()

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页