data class:
data class为“数据类”;同时会⽣成以下方法:
- toString()
- hashCode()
- equals()
- copy() (会返回一个新的对象)
- componentN() ...
解构:
定义为data class后,可以把⼀个对象的构造函数参数值「解构」成多个变量;
在解构变量时,所在对象对象的构造器函数里必需要持有相同参数值 data class CodeView(var code: String, var message: String, var body: String) { fun test() { val (code1, message1, body1) = CodeView("1", "2", "3") } }
Elvis 操作符:
可以通过
?:
的操作来简化
if null
的操作
// lesson.date 为空时使⽤默认值
val date = lesson.date?: "⽇⽇期待定"
// lesson.state 为空时提前返回函数
val state = lesson.state?: return
// lesson.content 为空时抛出异常
val content = lesson.content ?: throw
IllegalArgumentException("content expected")
下面示例代码中,code如果是null,就赋值给value"111",否则就赋值code
class CodeView {
var code: String? = null
var value: String = code ?: "111"
}
相等性:
- == 结构相等 (调⽤ equals() ⽐较 )
- === 引⽤(地址值)相等
when 操作符:
when
表达式可以接受返回值,多个分⽀相同的处理⽅式可以放在⼀起,⽤逗号分隔。
val colorRes = when (lesson.state) {
Lesson.State.PLAYBACK, null -> R.color.playback
Lesson.State.LIVE -> R.color.live
Lesson.State.WAIT -> R.color.wait
}
when 表达式可以⽤来取代 if-else-if 链。如果when的括号内不提供参数,所有的分⽀条件都是布尔表达式val colorRes = when { (lesson.state == Lesson.State.PLAYBACK) -> R.color.playback (lesson.state == null) -> R.color.playback (lesson.state == Lesson.State.LIVE) -> R.color.live (lesson.state == Lesson.State.WAIT) -> R.color.wait else -> R.color.playback }
operator:
通过
operator
修饰「特定函数名」的函数,例如
plus
、
get
,可以达到重载运算符的效果。
![](https://i-blog.csdnimg.cn/blog_migrate/038e7059fed19d8a7c67cda7596aa871.png)
lambda:
如果函数的最后⼀个参数是
lambda
,那么
lambda
表达式可以放在圆括号之外:
lessons.forEach(){ lesson : Lesson ->
// ...
}
如果你的函数传⼊参数只有⼀个 lambda 的话,那么⼩括号可以省略的:lessons.forEach { lesson : Lesson -> // ... }
如果 lambda 表达式里只有⼀个参数名,那么可以省略参数名,通过编译器提供的隐式 it 来访问lessons.forEach { // it // ... }
嵌套函数:
在函数中继续声明函数。
- 内部函数可以访问外部函数的参数
- 每次调⽤时,会生成一个额外的对象;所以在确实可以提高代码可读性的情况下使用,否则最好不要用。
fun func(){
fun innerFunc(){
}
}
函数简化:
可以通过符号 = 简化原本直接 return 的函数
fun get(key :String) = SP.getString(key,null)
示例未简化的时候:
fun test(): String {
return ""
}
示例简化的时候:
fun test(): String= ""
因为有类型推断,所以返回值也可以简化
fun test() = ""
函数参数默认值:
可以通过函数参数默认值来代替 Java 的函数重载
// 使⽤ @JvmOverloads 对 Java 暴露重载函数
@JvmOverloads
fun toast(text: CharSequence, duration: Int =
Toast.LENGTH_SHORT) {
Toast.makeText(this, text, duration).show()
}
上面这个方法在调用时,如果传入一个参数,则第二个默认值生效,如果传入两个参数,第二个默认值失效。
@JvmOverloads注解是对Java暴露重载函数,如果不加该注解,Java调用该函数时必须要传入两个参数。
扩展函数:
- 扩展函数可以为任何类添加上⼀个函数,从⽽代替⼯具类
- 扩展函数和成员函数相同时,成员函数优先被调⽤
- 扩展函数必须是静态函数(顶层函数或者@JvmStatic注解的函数)
下面示例是顶层函数
package com.example.myapplication.kt
fun Float.dp2px(): Float {
return 1f
}
object CodeView {
}
调用
6f.dp2px()
函数类型:
函数类型主要分为两步
- 调用函数的时候在参数内传入函数
- 函数的实现体在参数内接收一个函数
函数类型由「传⼊参数类型」和「返回值类型」组成,⽤「 -> 」连接,传⼊参数需要⽤「 () 」,如果返回值为 Unit 不能省略 函数类型实际是⼀个接⼝,我们传递函数的时候可以通过「 ::函数名 」,或者「匿名函数」或者使⽤ 「 lambda 」
class CodeView { fun codeViewRun(codeView: (CodeView) -> Unit) { } } fun main() { val codeView = CodeView() codeView.codeViewRun(::run1) } fun run1(codeView: CodeView) { }
内联函数:
- 内联函数配合「函数类型」,可以减少「函数类型」⽣成的对象
- 使⽤ inline 关键字声明的函数是「内联函数」,在「编译时」会将「内联函数」中的函数体直接插⼊到调⽤处。
object CodeView {
inline fun test() {
var value = ""
}
fun code() {
test()
}
}
上面代码,编译器经过编译后,生成的代码是:
object CodeView {
fun code() {
var value = ""
}
}
因为内联函数是直接将函数体里的代码拷贝到调用处的,所以在内联函数里应该避免具体实现的代码,而应该存放一些已经实现逻辑的函数体调用,经过内联函数的包装后调用,在提高阅读的前提下,同时减少调用栈。
具体化的类型参数:因为内联函数的存在,我们可以通过配合 inline + reified 达到「真泛型」的效果在未使用具体化类型参数的时候是这样声明和调用的 class CodeView { fun <T> create(clazz: Class<T>) { } fun test() { create(CodeView::class.java) } } 使用具体化类型参数是这样声明和调用的 class CodeView { inline fun <reified T> create() { var aClass = T::class.java } fun test() { create<CodeView>() } }