Kotlin学习笔记20 阶段复习2

参考链接

示例来自bilibili Kotlin语言深入解析 张龙老师的视频

lambda表达式 内联函数

Kotlin学习笔记 第三章 函数 高阶函数 lambda表达式 内联函数_积跬步 至千里-优快云博客_kotlin最佳实践

解构声明 集合 集合的扩展方法 Range 异常 Throw关键字

Kotlin学习笔记 第四章 解构声明 集合集合的扩展方法 Range 异常 Throw关键字_积跬步 至千里-优快云博客

注解

Kotlin学习笔记 第四章注解_积跬步 至千里-优快云博客

Kotlin调用Java

Kotlin学习笔记 第四章Kotlin调用Java_积跬步 至千里-优快云博客

Java调用Kotlin

Kotlin学习笔记 第四章 Java调用Kotlin_积跬步 至千里-优快云博客

反射

Kotlin学习笔记17 反射Part1_积跬步 至千里-优快云博客

Kotlin学习笔记18 反射Part2_积跬步 至千里-优快云博客

-------------------------------------------------

函数相关

1.函数的默认参数

2.函数最后一个参数是一个函数  函数最后一个参数是一个lambda表达式 可以将其移动到小括弧外部

3.Kotlin可变参数vararg 一般位于参数最后一个的位置(但是也可不在最后一个位置 如果vararg不是最后一个参数 那么可变参数后面的参数需要通过具名参数进行传递 如果其后的参数是函数类型 可以通过圆括号外部传递lambda表达式来实现 )

4.* spread operator 分散运算符

5.具名参数 在Kotlin中调用Java代码时不能使用具名参数 因为Java字节码不总是会保留参数名信息

6.单表达式函数 当函数返回单个表达式时,可以省略花括号并且在 = 符号之后指定代码体即可

7.显式返回类型 拥有方法体或者说块体的方法(即花括号)需要定义显式的返回类型 除非该方法返回Unit,Kotlin 不会推断拥有方法体或者说块体的方法的返回值类型 因为这种函数可能有非常复杂的控制流程 对于阅读代码的人和编译器来说 返回类型不是那么明显了 因此Kotlin统一不对所有显示返回类型的方法做类型推断

8.中缀符号 (infix notation) 具体作用主要是 忽略该调用的点与圆括号 函数定义成中缀函数有3个条件

 a 是成员函数或扩展函数 (依赖于某一个类)

 b 只有一个参数 且没有默认值(不可以是可变参数)

 c 使用infix修饰

9 内联函数

9.1 内联函数的目的

以下为个人理解

函数之间的调用会有函数堆栈 进入下一个函数前 当前函数的信息会以存入堆栈 知道从下一个函数返回才会取出

因此 函数调用层级越高 会导致调用堆栈异常庞大 在递归函数中如果发生无法终止递归的情况 会一直运行直到堆栈溢出

内联函数的目的是为了避免函数堆栈过大设计出来的

调用到内联函数时 会将该函数复制到调用处 这样 在同一个函数里 就不会创建创建函数调用堆栈存放数据了

2.2 内联函数的缺点

以下为个人理解

虽然内联函数一定程度上降低了调用堆栈的高度 但是 如果内联函数被调用的次数太多 那么就需要不断的拷贝

这种操作消耗的资源也不见得很小 所以 内联函数的作用其实有限

-------------------------------------------------

Lambda 表达式相关

1.Lambda表达式有时候可以省略参数类型 返回值类型

2.下划线 变量占位符 如果变量在函数中没有使用 可以使用变量占位符代替

3.Lambda表达式 当只有一个参数时 可以用it代替

4.Lambda表达式的参数可以是函数 函数实际只是个形参 规定了外部传入的函数接受参数和返回类型 具体算法由外部决定

5.ambda表达式的返回值  在默认情况下 lambda表达式的最后一句话会作为该lambda表达式的返回值 我们可以全限定的return语法显示从lambda表达式返回值

全限定的return语法 会使用到标签 用法为return@方法名 用来表示lambda的返回

6.匿名函数

     * 匿名函数与普通函数的区别

     * 匿名函数的参数类型如果可以推断出来 可以省略

     * 匿名函数不能之间定义在顶层(因为那样就无法调用了)

     * 匿名函数所有参数必须在圆括号中 参数是lambda表达式也一样

     * 匿名函数主要可以代替lambda表达式 (实际意义不大)

     * 匿名函数的return是返回匿名函数本身 而lambda表达式则不同 直接return表示返回到外层函数

     * 匿名函数的使用开起来不如lambda 了解即可

7 闭包  Lambda 表达式或者匿名函数(以及局部函数和对象表达式) 可以访问其闭包 , 即在外部作用域中声明的变量。

8 带有接收者的函数字面值 

这个功能及其类似扩展函数

带有接收者的函数类型,例如 A.(B) -> C,可以用特殊形式的函数字面值实例化—— 带有接收者的函数字面值。

     * 如上所述,Kotlin 提供了调用带有接收者(提供接收者对象)的函数类型实例的能力。

     * 在这样的函数字面值内部,传给调用的接收者对象成为隐式的this,以便访问接收者对象的成员而无需任何额外的限定符,亦可使用this表达式访问接收者对象。

     * 这种行为与扩展函数类似,扩展函数也允许在函数体内部访问接收者对象的成员。

9 函数字面值扩展

     * 带有接收者类型的函数的非字面值 可以作为参数传递 前提是所需要接受函数的地方应该有一个接收者类型的参数

     * 例如类型 String.(Int) -> Boolean 等价于 (String,Int) -> Boolean

-------------------------------------------------

解构声明

 * 可以理解为批量赋值 常用于数据类和Map等拥有多个属性的类型

 * 目的是方便我们声明和获取其中的属性

1. 解构声明在数据类中的应用

2. 一个函数返回多个结果 --使用Pair或Triple

3. 解构声明在集合中的应用 利用解构声明遍历map

-------------------------------------------------

集合相关

kotlin 严格区分可变集合和不可变集合

重点是区分真正的不可变集合与可变集合的只读视图

在kotlin中 mutable修饰的集合是可变的 没有mutable修饰的则是不可变的

例如 MutableList创建的是可变集合 List创建的是不可变集合

 List继承自Collection Collection又继承自Iterable 因此 List只有访问的方法

MutableList除了继承自 List 还继承自MutableCollection MutableCollection则提供了一系列add remove等修改list内容的方法

只读视图虽然本身无法修改内容 但是如果它的原引用内容变化 视图里面的内容也发生变化

声明一个只读视图(如List)指向一个可变集合(如MutableList<String>) 即创建一个可变集合的只读视图

range

-------------------------------------------------

异常

Kotlin 中的异常是一个表达式(要么是try的返回值 要么是catch的返回值)

Kotlin 中所有的异常都是运行时异常 没有checked exception

throw在Kotlin中是一个表达式

throw表达式的类型是一种特殊的类型:Nothing

在自己的代码中 可以使用Nothing来代表永远不会返回的函数

Elvis 表达式 Elvis是 ?: 它的含义是 如果该表达式的前半部分不为空 则该表达式的值为前半部分 否则为后半部分

普通变量赋值为null 类型推断为Nothing?

list元素赋值为null list类型推断为List<Nothing?>

---------------------------------------------------

注解

Kotlin注解和Java类似

元注解:定义注解的注解 如:

@Target 表示当前annotation使用在哪个位置

@Retention 表示当前注解是运行时注解还是编译时注解等

@Repeatable 表示当前注解是否可以在同一个元素重复使用

@MustBeDocumented 表示当前注解是API 文档的一部分

其他注解

@field 表示用在Java 属性值上

@get 表示用在该属性的get方法

@param 表示用在构造方法的参数上

@file:JvmName("CustomerName") 表示当前文件生成的build文件变更为CustomerName.class

注解也可以拥有自己的构造方法

注解的构造方法的参数类型可以是:

 * Java里面定义的基本数据类型(Int,Long...)

 * 字符串类型

 * classes (MyClass::class)

 * 枚举

 * 其他注解

 * 上述类型的数组类型

Kotlin 注解不允许为空

如果某个注解是另外一个注解的参数 这个注解使用的时候不需要以@开头

注解中带有class作为参数的注解 如果某个注解中包含class作为参数 那么需要使用Kotlin class(KClass) Kotlin编译器会将其自动转换为Java class 这样 Java代码才能正常看到注解和参数

3 注解使用处目标 (use-site target) 指明注解是用在何处

 * 在对类的属性或是主构造方法的参数声明注解时 会存在多个Java元素可以通过对应的Kotlin元素生成出来,

 * 因此 在生成的Java字节码中 可能存在多个可能的位置用于生成注解 (即注解存在二义性或多义性 不知道这个注解是加在什么东西上的)

 * 如想确定注解是加到什么东西上 可以使用注解使用出目标对注解进行进一步修饰

----------------------------------------

Kotlin调用Java

1 Kotlin调用Java代码时 Kotlin的空检查可能会失效

在Java中 所有引用都可能为null 在Kotlin中 对null有着严格限制

在Kotlin中 将来自Java的声明类型称为平台类型(Platform Types)

对于这种类型(平台类型)来说 Kotlin的null检查会变得缓和 不再那么严格.

这么做的目的是使得空安全的语义在Java和Kotlin中保持一致

当我们调用平台类型引用的方法时 Kotlin就不会在编译期间施加空安全检测 使得编译可以通过

但是在运行时可能抛出异常 因为平台类型的引用值可能为空

2 kotlin 非空检查的原理: 如果声明一个非空类型 则会在该变量赋值时产生一个断言 断言赋值不为空 如果断言失败 则编译期就报错

如果我们使用了不可空的类型 编译器会在赋值时生成一个断言。这会防止Kotlin的不可空变量持有一个null值;这一点也适用于方法的参数传递我们在一个平台类型值传递到不可空的参数或方法参数时 也同样会生成这个断言 但是该断言只能检测明显空的情况

总体来说 Kotlin会竭尽所能防止null赋值蔓延到程序的其他地方 而是在问题发生时就立刻通过断言来解决

3 Java与Kotlin在数组 上的区别

Kotlin中的数组是不变的(相对于协变和逆变) 这一点和Java不同(Java是协变的)

因此 Java的数组设计是有问题的

这意味着 我们无法在Kotlin中将Array<String> 赋值给Array<Any> 可以避免运行时异常

Kotlin提供了原生类型数组来避免自动装修拆箱带来的成本:IntArray,DoubleArray,CharArray...

Array相当于Java里面的ArrayList<xx>

而IntArray DoubleArray CharArray等相当于Java里面的int [], double[], char[]等等

4 Kotlin调用Java 异常

调用Java的需要处理异常的方法 Kotlin不需要对异常进行处理

---------------------------------------------------

Java调用Kotlin

1 属性 (properties)

 * 一个Kotlin的属性会被编译为3个部分

 * 1.一个get方法

 * 2.一个set方法

 * 3.一个私有field域(field)

 *

 * 如果Kotlin的属性以is开头 那么set get方法会发生一些变化

 * get方法方法名与属性名一致

 * set方法会将is替换为set

 * 这种规则适用于所有类型的属性 不一定时Boolean类型

我们无法通过new关键字创建由Kotlin编译器生成的以Kt结尾的类的实例

因为在生成的字节码中 没有为以Kt结尾的类生成任何构造方法

反而是对应的没有以Kt结尾的类 是有构造方法的

2 @JvmField 会将普通的实例变量 变化成 类变量

3 @JvmField 修饰伴生对象的filed 该属性变成伴生对象的类变量 没有了set get方法

4 @JvmStatic修饰伴生对象的方法 在Kotlin中 可以将具名对象或者伴生对象中定义的函数注解为@JvmStatic 这样编译器会机会再相应对象的类中生成静态(类)方法 也会在在相应的类中生成实例方法  即 在companion对象中生成test1方法 在MyPeople也生成test1方法 且MyPeople.test1方法内部调用的是companion.test1

5 @JvmName修饰方法 可以更改在Java调用Kotlin时 使用的Kotlin方法的名称

6 Java调用Kotlin带有默认参数的构造方法 加上@JvmOverloads 便可以使Java调用Kotlin方法时 可以使用省略参数

7 @Throws 

Java调用Kotlin抛出检查时异常的方法(Java不异常终止) Throws 注解告诉Java文件 该方法会抛出异常

---------------------------------------------------------

反射

1 获取Java class和Kotlin KClass的方法

2 通过实例(而不是类名) 获取自定义类的Kotlin以及Java 对象

3 函数引用

可以传入函数作为参数

函数类型如果能从上下文推断 那么支持重载

::multiplyBy3表示例如类似函数类型 (Int)->Int 或者 (String) ->Int的值等等

如果该方法不是来自顶层的方法 而是某个类的普通方法或者扩展方法 需要加上类的索引

4 函数组合

5 属性引用(Method Reference)

属性引用与之前的函数引用的用法完全一致 通过::属性名 的形式调用

KProperty0继承自KProperty KProperty继承自KCallable

KClass和KProperty有点像 只不过KClass是Kotlin对应Java的Class  KProperty基本是Kotlin对应Java的Field

6 属性引用作为方法使用

7 通过属性引用调用扩展属性

8 获取KClass Class等对象的对比示例

9 使用构造方法的引用(Constructor Reference)

 * 要使用构造方法的引用 有如下要求

 * 1 函数对象的参数与构造方法的参数一致(包括参数个数 顺序 类型)

 * 2 函数返回对象类型与构造方法创建类型一致

10 获取特定对象实例的属性和方法

11 Java反射和Kotlin反射各种对应关系

 * Java   Kotlin

 * Class  KClass

 * Method KFunction

 * Field  KProperty

 * 当然 并不是完全等价 例如与KProperty类似的还有KMutableProperty KProperty0 KMutableProperty0等等

12 通过KClass获取泛型类型参数

13 通过KClass获取一个类的父类信息

14 通过KClass获取一个类的属性信息

15 通过KClass获取一个类的普通方法

16 通过KClass获取一个类的构造方法

17 通过KClass获取一个类的普通方法并调用

18 通过KClass获取一个类的属性并调用其get方法

19 通过KClass获取一个类的属性并get set它的值

20 通过KClass获取一个类的伴生对象 并反射调用伴生的方法

21 通过KClass反射创建实例

22 通过KClass反射调用有参构造方法

23 通过KClass获取一个类的普通方法并调用

24 通过KClass获取一个类的属性并get set它的值(通过判断属性名称 并使用KMutableProperty1或KProperty1 调用  可以对比19的例子)

25 顶层变量的反射 vs 普通变量的反射调用

26 查找一个用作Kotlin属性的getter的幕后字段或Java方法

   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值