1. 什么是 kotlin?
kotlin 是静态类型的编程语言,运行于 jvm 之上。如果在编译时知道变量的类型,则语言是静态类型的,在运行时知道变量类型,则语言是动态类型。
2. 什么是 extension(扩展)函数
Kotlin 可以对一个类的属性和方法进行扩展,对被扩展的类代码本身不会造成任何影响。 扩展函数可以为已经存在的类添加新的方法,并且不会修改原来的类。
代码语言:javascript复制class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
User("libo", 10).login()
}
fun User.login() {
Log.i("TAG","去登录")
}
}
data class User(var name: String, var age: Int)
3. 在 kotlin 中有多少种构造函数
kotlin 将构造函数分为了两种: 主构造函数和次构造函数。
代码语言:javascript复制//主构造方法如下,跟在类名后面
class Person constructor(name:String){
}
//无参主构造方法
class Person constructor(){
}
//当主构造方法没有任何注解或者可见性修饰符时,可以省略,写成下面这样
class Person {
}
代码语言:javascript复制class Person {
/**
* 无参次构造方法
*/
constructor(){
}
/**
* 有参次构造方法
*/
constructor(name:String){
}
}
主构造函数没有函数体,如果我们想在主构造函数中写一些逻辑,怎么办呢, kotlin 给我们提供一个 init 结构体,所有构造函数中的逻辑都可以写在里面:
代码语言:javascript复制class Person(val name: String, val age: Int) : Person() {
init {
println("name is $name")
println("age is $age")
}
}
4. lateinit 和 by lazy 的区别
Kotlin 基于 Java 的空指针提出了一个空安全的概念,即每个属性默认不可为 null。在某个类中,如果某些成员变量没办法在一开始就初始化,并且又不想使用可空类型(也就是带?的类型)。那么,可以使用 lateinit 或者 by lazy 来修饰它。
- lateinit 只能用于修饰变量 var,不能用于可空的属性和 Java 的基本类型。
- lateinit 可以在任何位置初始化并且可以初始化多次。
- lazy 只能用于修饰常量 val,并且 lazy 是线程安全的。
- lazy 在第一次被调用时就被初始化,以后调用该属性会返回之前的结果。
5. let, apply, run, with 的区别
6. 高阶函数
如果一个函数接收另一个函数作为参数,或者返回类型是一个函数,那么这个函数我们就称之为高阶函数。
举例如下,这些函数用法与 Rxjava 同名函数类似
代码语言:javascript复制//forEach,用于遍历集合
val arr = intArrayOf(1, 2, 4, 6)
arr.forEach {
println(it)
}
//map 返回一个每一个元素根据给定的函数转换所组成的List
val arr = intArrayOf(1, 2, 4, 6)
val newArr = arr.map { (it * 2).toString() }
println(newArr)
//flatMap 遍历所有的元素 ,为每一个创建一个集合 ,最后把所有的集合放在一个集合中
val arr = intArrayOf(1, 2, 4, 6)
val arr2 = intArrayOf(10, 39, 39, 18, 88)
var arr3 = intArrayOf(100, 200, 383, 198)
arrayListOf(arr, arr2, arr3).flatMap { iterator ->
iterator.map {
println(it.toString())
}
}
//filter,用于过滤数据
val arr = intArrayOf(1, 2, 7, 6, 10, 39, 39, 18, 88)
arr.filter {
//这里是通过条件
it % 2 == 0
}
//takeWhile,带满足条件的过滤
//它的实现和filter不同地方在filter总是会遍历当前IntArray的所有元素,而takeWhile在第一次发现元素不满足的时候就不再遍历
val arr = intArrayOf(1, 2, 4, 6, 8, 9, 10, 12, 14)
arr.takeWhile {
it % 2 == 0
}
//take/takeLast
val arr = intArrayOf(1, 2, 4, 6, 8, 9, 10, 12, 14)
var list = arr.take(5) //取前5个
var list2 = arr.takeLast(3) //取后3个
7. 伴生对象的总结
类似于 Java 中使用类访问静态成员的语法。因为 Kotlin 取消了 static 关键字,所以 Kotlin 引入伴生对象来弥补没有静态成员的不足。可见,伴生对象的主要作用就是为其所在的外部类模拟静态成员。
注意:
- 每个类可以最多有一个半生对象;
- 使用 const 关键字修饰常量,类似于 Java 中的 static final修饰。
- 可以使用 @JvmField 和 @JvmStatic 类似于 Java 中调用静态属性和静态方法;
- 伴生对象可以扩展属性和扩展方法。
8. init 代码块和构造方法以及伴生对象中代码的调用时机
创建 Person 类,创建 person 对象打印方法调用时机:
代码语言:javascript复制class Person {
private var name: String = "jack"
constructor() {
println("constructor 方法调用")
}
init {
println("init 方法调用")
}
companion object {
init {
println("companion init 1")
}
}
}
从 Tools-->kotlin-->show Kotlin Bytecode,将 Person 类反编译成 java 类得到:
伴生对象转为了静态代码块,init 代码块插入到了构造方法的开头处。静态代码块在编译期运行,然后依次运行构造方法的代码。打印的结构为:
结论:伴生对象先于init方法,再先于构造方法。首先伴生对象中的代码是在类加载时就会执行。init代码块中的方法会按顺序放在主构造函数中,主构造函数中原来的代码会在后面执行。
9. const 和 val 有什么区别?
所述 const 关键字被用于声明那些不可变在本质即,这些属性是只读属性的属性。 但是,这些属性的值必须仅在编译时已知,这 const 就是也称为编译时常量的原因。相当于 java 中的 static final 修饰。该val关键字还用于只读属性。但是 const 和之间的主要区别在于 val,val 属性也可以在运行时进行初始化,即不可变变量。
10. Kotlin data 类机制
创建 DataBean 类:
代码语言:javascript复制class DataBean(var uId: Int, val phoneNum: String, val address: String)
转成 java 类,知道为什么 Kotlin 开发强大了吧。
代码语言:javascript复制public final class DataBean {
private int uId;
@NotNull
private final String phoneNum;
@NotNull
private final String address;
public final int getUId() {
return this.uId;
}
public final void setUId(int var1) {
this.uId = var1;
}
@NotNull
public final String getPhoneNum() {
return this.phoneNum;
}
@NotNull
public final String getAddress() {
return this.address;
}
public DataBean(int uId, @NotNull String phoneNum, @NotNull String address) {
Intrinsics.checkNotNullParameter(phoneNum, "phoneNum");
Intrinsics.checkNotNullParameter(address, "address");
super();
this.uId = uId;
this.phoneNum = phoneNum;
this.address = address;
}
}
反编译成 java 代码后自动生成了变量的 get、set 方法,equals 方法,copy 方法,hashCode() 方法。如果这些函数中的任何一个在类体中显式定义或继承自其基类,则不会自动生成该函数。如果变量是 val 修饰,只会生成 get 方法。
11. 什么是 Range 操作符?
Range 是 Kotlin 相对 Java 新增的一种表达式,它表示的是值的范围,类似于数学中的区间。 Range 的表达式是像这样子的:1..20,其中..是运算符,它表示一个闭区间 [1, 20]。