Kotlin 笔记
函数
方法是一种特殊的函数,它必须通过类的实例调用,也就是说每个方法可以在方法内部拿到这个方法的实例。这是方法和函数的不同之处。
方法和函数几乎一模一样,唯一的区别就是方法必须声明在类里面。
返回 Nothing
如果一个函数不会返回(也就是说只要调用这个函数,那么在它返回之前程序肯定退出了(比如一定会抛出异常的函数)), 因此你也不知道返回值该写啥,那么你可以让它返回 Nothing。
返回 Unit
如果一个函数不返回东西,你可以不写返回值。也可以让它显示返回 Unit
1 | fun square(int: Int) = int * int |
fun xxx() = Unit 表示这是一个空函数。
内部函数
函数体内定义的函数。
1 | fun myfun(){ |
中缀表达式
其实是 Kotlin 方法的一种语法糖,一个方法如果在声明时有一个 infix 修饰符,那么它可以使用中缀语法调用。
所谓中缀语法就是不需要点和括号的方法调用
1 | class B |
操作符重载
Kotlin 的操作符重载的规则是
- 该方法使用
operator修饰符
- 该方法的方法名必须被声明为特定的名称,以将对应的操作符映射为这个函数的调用
- 参数必须符合该操作符的规定,比如+的重载就不能有多于一个(不含)的参数,也不能为空参数。
eg:
1 | class A { |
函数的柯里化
高阶函数
- 高阶函数:以另一个函数作为参数或者返回值的函数
- 函数类型:参数类型->返回类型,Unit 不能省略
内联函数
内联函数最好的好处就是直接内联 Lambda,不产生匿名内部类对象。
扩展函数
使用一些语法糖来假装给一些类添加方法,并像真正的方法一样调用它。
扩展 Lambda
泛型扩展
Lambda 表达式
1 | //Lambda对象有缺省的invoke函数的实现 |
Lambda 经常作为函数参数使用。
一些约定
- 如果 lambda 表达式作为函数最后一个实参,可以将 lambda 表达式放到括号外面;
- 当 lambda 作为函数唯一的一个实参时,可以将函数括号直接省略;
- 当有多个实参时候,即可以选择把 lambda 留在括号内强调它是一个实参,也可以放到括号外边;
常见的符号
$
:字符串模板?
:表示这个对象可能为空?:
:Elvis 操作符1
val length = name?.length ?: -1
!!
:表示该对象不为 null,否则调用时会抛出 NPE==
:比较对象的值;===
:比较对象的地址;..
:表示区间1
2if (i in 1..10) // [1, 10]
for (i in 1..4 step 2)// "13"_
:不需要指定名称的变量,类似占位符::
:表示把一个方法当做一个参数,传递到另一个方法中进行使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17fun main() {
val user = User()
// result is {a , b}
println(user.lock("a", "b", user::getResult))
}
class User {
fun getResult(str1: String, str2: String): String = "result is {$str1 , $str2}"
fun lock(p1: String, p2: String, lambda: (str1: String, str2: String) -> String): String {
return lambda(p1, p2)
}
}
listOf("Hello", "World").forEach(::println)
```得到 Class 对象,如:String::class.java
1
2
3
4
5
6
7
8
9// package kotlin.jvm
public val <T> KClass<T>.java: Class<T>
get() = (this as ClassBasedDeclarationContainer).jClass as Class<T>
// reified 实化范型参数
inline fun <reified T : Activity> openActivity() {
startActivity(Intent(this, T::class.java))
}判断 lateinit 变量是否初始化
1
2
3
4private lateinit var name: String
if (::name.isInitialized) {
//...
}
@
:限定 this 的类型
1
2
3
4
5
6
7
8
9
10
11class User {
inner class State {
fun getUser(): User {
return this@User
}
fun getState(): State {
return this@State
}
}
}作为标签
1
2
3
4
5
6
7loop@ for (i in list) {
for (j in list2) {
if (1 == j) {
break@loop
}
}
}
关键字
lateinit
延迟初始化变量。
在编译层面上,kotlin 的编译器不会做这种检查。如果你将变量声明为 lateinit,它就认为你肯定会初始化,至于你是怎么初始化它的,它就不管了。
如果一个变量声明为 lateinit,但是没有初始化,而又被使用了的话,会抛出一个异常 UninitializedPropertyAccessException。在访问的变量的那个地方,插入
ifnonnull
字节码指令,检测是否为 null。类似
by lazy
:1
2
3val name: String by lazy {
"Vance"
}by lazy 和 lateinit 的区别:
- by lazy 修饰 val 的变量
- lateinit 修饰 var 的变量,且变量是非空的类型
object
可以用来声明单例对象、伴生对象,匿名对象
生对象
- 每个类可以最多有一个半生对象
- 伴生对象的成员类似于 Java 的静态成员
- 使用 const 关键字修饰常量,类似于 Java 中的 static final 修饰
- 可以使用 @JvmField 和 @JvmStatic 类似于 Java 中调用静态属性和静态方法
- 伴生对象可以扩展属性和扩展方法
lateinit
修饰变量,表示该对象延迟初始化,不用判 null。sealed
密封类。operator
运算符重载。internal
饰类和方法 限制不同 module 的访问。inner
只能用来修饰内部类。inline
内联函数。noinline
crossinline
让无法使用内联函数的方法使用内联函数。infix
中缀表达式。- 必须是成员函数或扩展函数;
- 必须只有一个参数;
- 其参数不得接受可变数量的参数且不能有默认值。
1
2
3
4
5
6
7infix fun String.begin(prefix: String): Boolean = startsWith(prefix)
val result = "Hello" begin "A"
public infix fun Int.until(to: Int): IntRange {
if (to <= Int.MIN_VALUE) return IntRange.EMPTY
return this .. (to - 1).toInt()
}by
类或属性委托。
注解
@JvmOverloads
生成重载,如果你写一个有默认参数值的 Kotlin 函数,在 Java 中只会有一个所有参数都存在的完整参数签名的方法可见,如果希望向 Java 调用者暴露多个重载,可以使用
@JvmOverloads
注解。-
不会为属性生成 getters/setters 方法且,变量不能用 private 修饰。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23class User(id: String) {
val ID = id
}
// 编译成字节码后,反编译成 Java 代码
public final class User {
public final String ID;
public User( String id) {
Intrinsics.checkNotNullParameter(id, "id");
super();
this.ID = id;
}
}
// Java
class JavaClient {
public String getID(User user) {
return user.ID;
}
} @JvmStatic
生成静态的 setter/getter 方法。@JvmName
指定生成的类名或方法名称。如果作用在顶级作用域(文件中),则会改变生成对应 Java 类的名称。如果作用在方法上,则会改变生成对应 Java 方法的名称。eg: @file:JvmName(“FooKt”),@JvmName(“foo1”)@JvmMultifileClass
配合 @JvmName 使用,指定生成到同一个文件中。@JvmOverloads
生成重载方法,供 Java 调用。@Throws
由于 Kotlin 语言不支持 CE(Checked Exception),而 Java 语言通过 throws 关键字在方法上声明 CE。@Synchronized @Volatile @Transient
分别对应 Java 中的 Synchronized volatile transient 关键字。@JvmWildcard
用于处理泛型参数。@JvmSuppressWildcards
用来抑制通配符泛型参数的生成,即在不需要型变泛型参数的情况下,我们可以通过添加这个注解来避免生成型变泛型参数。@JvmDefault
用于在接口中处理默认实现的方法。