在本文中,将分享一些在 Android 面试中被问到的比较多的Kotlin 相关问题。所以,如果你正在准备 Android 面试,那么这篇文章对你来说是很有必要看的,或者收藏起来,转载起来...
对每个问题都提供了简短明了的答案,此外,您也可以通过该链接。
1. Kotlin 如何在 Android 上运行?
就像 Java 一样,Kotlin 代码也被编译成 Java 字节码,并在运行时由 Java 虚拟机即 JVM 执行。当一个名为 Kotlin 的文件Main.kt被编译后,它最终会变成一个类,然后生成该类的字节码。字节码文件的名称将是MainKt.class,并且该文件将由 JVM 执行。
2. 为什么要使用 Kotlin?
Kotlin 简洁
Kotlin 是空值安全的
Kotlin 是可互操作的
3. 用var和val声明变量有什么区别?
如果你想声明一些可变(可变)变量,那么你可以使用var. 对于不可变变量,使用valieval变量一旦赋值就不能改变。
4. 用val和const声明变量有什么区别?
声明的变量本质val上const都是不可变的。但是const变量的值必须在编译时知道,而val变量的值也可以在运行时分配。
5. Kotlin 中如何保证 null 安全?
使用 Kotlin 的主要优势之一是 null 安全性。在 Java 中,如果您访问一些 null 变量,那么您将获得一个NullPointerException. 因此,Kotlin 中的以下代码将产生编译时错误:
var name: String = "码农乐园"
name = null //error
因此,要将空值分配给变量,您需要将name变量声明为可空字符串,然后在访问此变量期间,您需要使用安全调用运算符,即?.
var name: String? = "码农乐园"
print(name?.length) // ok
name = null // ok
6.安全调用(?.)和空值检查(!!)有什么区别?
安全调用运算符 ie?.用于检查变量的值是否为空。如果为 null 则返回 null ,否则返回所需的值。
var name: String? = "码农乐园"
println(name?.length) // 8
name = null
println(name?.length) // null
如果要在变量值为 null 时抛出 NullPointerException,则可以使用 null 检查或!!运算符。
var name: String? = "码农乐园"
println(name?.length) // 8
name = null
println(name!!.length) // KotlinNullPointerException
7. Kotlin 中是否有像 java 一样的三元运算符?
不,我们在 Kotlin 中没有三元运算符,但您可以通过 if-else 或 Elvis 运算符来使用三元运算符的功能。
8. Kotlin 中的 Elvis 运算符是什么?
在 Kotlin 中,您可以使用 null 安全属性将 null 值分配给变量。要检查一个值是否具有空值,那么您可以使用 if-else 或可以使用 Elvis 运算符?:,例如:
var name:String? = "码农乐园"
val nameLength = name?.length ?: -1
println(nameLength)
上面使用的 Elvis 运算符(?:)将返回 name 的长度,如果 value 不为 null,否则如果 value 为 null,则返回-1。
9. 如何将 Kotlin 源文件转换为 Java 源文件?
将 Kotlin 源文件转换为 Java 源文件的步骤:
在 IntelliJ IDEA / Android Studio 中打开您的 Kotlin 项目。
然后导航到工具 > Kotlin > 显示 Kotlin 字节码。
现在单击反编译按钮以从字节码中获取您的 Java 代码。
10、@JvmStatic、@JvmOverloads、@JvmFiled 在 Kotlin 中有什么用?
@JvmStatic:这个注解用来告诉编译器该方法是静态方法,可以在Java代码中使用。
@JvmOverloads:要在 Java 代码中使用 Kotlin 代码中作为参数传递的默认值,我们需要使用@JvmOverloads注解。
@JvmField:要在不使用任何 getter 和 setter 的情况下从 Java 代码访问 Kotlin 类的字段,我们需要@JvmField在 Kotlin 代码中使用。
11. Kotlin 中的数据类是什么?
数据类是那些仅用于存储一些数据的类。在 Kotlin 中,它被标记为数据。以下是相同的示例:
data class Developer(val name: String, val age: Int)
当我们将一个类标记为数据类时,您不必像我们在 Java 中那样实现或创建以下函数:hashCode()、equals()、toString()、copy()。编译器会在内部自动创建这些,因此也可以生成干净的代码。虽然,数据类需要满足的其他要求很少。
12、Kotlin中可以使用int、double、float等原始类型吗?
在 Kotlin 中,我们不能直接使用原始类型。我们可以使用 Int、Double 等类作为基元的对象包装器。但是编译后的字节码具有这些原始类型。
13. Kotlin 中的字符串插值是什么?
如果您想在字符串中使用某个变量或执行某些操作,则可以使用字符串插值。您可以使用$符号来使用字符串中的某些变量,也可以在{}符号之间执行一些操作。
var name = "码农乐园"
print("Hello! I am learning from $name")
14. Kotlin 中的解构是什么意思?
解构是一种从存储在(可能是嵌套的)对象和数组中的数据中提取多个值的便捷方式。它可用于接收数据的位置(例如分配的左侧)。有时将一个对象分解为多个变量是很方便的,例如:
val (name, age) = developer
现在,我们可以独立使用姓名和年龄,如下所示:
println(name)
println(age)
从 MindOrks 博客了解有关 Kotlin 解构的更多信息。
15. Kotlin 中什么时候使用 lateinit 关键字?
lateinit是后期初始化。
通常,声明为非空类型的属性必须在构造函数中初始化。然而,这通常并不方便。
例如,可以通过依赖注入来初始化属性,或者在单元测试的 setup 方法中初始化属性。在这种情况下,您不能在构造函数中提供非 null 初始化程序,但您仍然希望在引用类主体内的属性时避免 null 检查。要处理这种情况,您可以使用 lateinit 修饰符标记该属性。
16. 如何检查一个lateinit变量是否已经初始化?
您可以在方法的帮助下使用它之前检查 lateinit 变量是否已初始化isInitialized。如果 lateinit 属性已初始化,则此方法将返回 true,否则将返回 false。例如:
class Person {
lateinit var name: String
fun initializeName() {
println(this::name.isInitialized)
name = "MindOrks" // initializing name
println(this::name.isInitialized)
}
}
fun main(args: Array) {
Person().initializeName()
}
17. Kotlin 中的 lateinit 和 lazy 有什么区别?
lazy 只能用于 val 属性,而 lateinit 只能用于 var,因为它不能编译为 final 字段,因此不能保证不变性。
如果您希望您的属性以一种事先可能未知的方式从外部初始化,请使用 lateinit。
18、==操作符和===操作符有什么区别?
是的。==运算符用于比较变量中存储的值,运算===符用于检查变量的引用是否相等。但是在原始类型的情况下,===操作符也会检查值而不是引用。
// primitive example
val int1 = 10
val int2 = 10
println(int1 == int2) // true
println(int1 === int2) // true
// wrapper example
val num1 = Integer(10)
val num2 = Integer(10)
println(num1 == num2) // true
println(num1 === num2) //false
19. Kotlin 中的 forEach 是什么?
在 Kotlin 中,要像在 Java 中一样使用 for-each 循环的功能,我们使用forEach函数。以下是相同的示例:
var listOfMindOrks = listOf("码农乐园", "阿福", "dom")
listOfMindOrks.forEach {
Log.d(TAG,it)
}
20. Kotlin 中的伴生对象是什么?
在 Kotlin 中,如果您想编写一个函数或任何可以在没有类实例的情况下调用的类成员,那么您可以将其编写为类中伴随对象的成员。
要创建伴生对象,您需要companion在对象声明前添加关键字。
以下是 Kotlin 中伴随对象的示例:
class ToBeCalled {
companion object Test {
fun callMe() = println("You are calling me :)")
}
}
fun main(args: Array) {
ToBeCalled.callMe()
}
21. Kotlin 中的 Java 静态方法等价物是什么?
要在 Kotlin 中实现类似于 Java 静态方法的功能,我们可以使用:
伴生对象
包级函数
目的
22. Kotlin 中的 FlatMap 和 Map 有什么区别?
FlatMap 用于将列表的所有项目组合成一个列表。
Map 用于根据特定条件转换列表。
23. Kotlin 中的 List 和 Array 类型有什么区别?
如果您有一个具有固定大小的数据列表,那么您可以使用数组。但是如果列表的大小可以变化,那么我们必须使用可变列表。
24. Kotlin中可以使用new关键字实例化一个类对象吗?
不,在 Kotlin 中,我们不必使用new关键字来实例化类对象。要实例化一个类对象,我们只需使用:
var varName = ClassName()
25. Kotlin 中的可见性修饰符是什么?
可见性修饰符或访问说明符或访问修饰符是一个概念,用于定义编程语言中某事物的范围。在 Kotlin 中,我们有四个可见性修饰符:
private:在包含声明的特定类或文件中可见。
protected:在特定类或文件中可见,并且在声明它的特定类的子类中可见。
internal:在该特定模块中的任何地方都可见。
公开:对所有人可见。
注意:默认情况下,Kotlin 中的可见性修饰符是public。
26. 如何在 Kotlin 中创建 Singleton 类?
单例类是这样定义的类,即只能创建该类的一个实例,并在我们只需要该类的一个实例的情况下使用,例如日志记录、数据库连接等。
要在 Kotlin 中创建 Singleton 类,您需要使用 object 关键字。
object AnySingletonClassName
注意:不能在对象中使用构造函数,但可以使用 init。
27. Kotlin 中的初始化块是什么?
init块是在主构造函数执行后立即执行的初始化块。一个类文件可以有一个或多个将串行执行的初始化块。如果你想在主构造函数中执行一些操作,那么在 Kotlin 中是不可能的,为此你需要使用init块。
28. Kotlin 中的构造函数有哪些类型?
主构造函数:这些构造函数是在类头中定义的,你不能在其中执行一些操作,这与 Java 的构造函数不同。
辅助构造函数:这些构造函数是在类体内使用构造函数关键字声明的。您必须从辅助构造函数显式调用主构造函数。此外,不能在辅助构造函数中声明类的属性。Kotlin 中可以有多个二级构造函数。
29、主构造函数和次构造函数之间有什么关系吗?
是的,当使用辅助构造函数时,您需要显式调用主构造函数。
30. 构造函数中使用的默认参数类型是什么?
默认情况下,val 中构造函数的参数类型。但是您可以将其显式更改为 var 。
31. Kotlin 中的协程是什么?
一个以更高效和更简单的方式管理并发的框架,其轻量级线程编写在实际线程框架之上,通过利用函数的协作特性来充分利用它。
同步的方式做异步事件
这是一个重要的面试问题。
https://juejin.cn/post/6954393446622691342
32. Kotlin Coroutines 中的挂起函数是什么?
挂起函数是 Kotlin 中协程的构建块。挂起函数是一个可以启动、暂停和恢复的函数。要使用挂起函数,我们需要在普通函数定义中使用挂起关键字。
33. Kotlin Coroutines 中 Launch 和 Async 有什么区别?
不同之处在于launch{}不返回任何内容,而是async{}返回 的实例Deferred
换一种说法:
发射:一劳永逸
async:执行任务并返回结果
34. Kotlin Coroutines 中的作用域是什么?
详情查看链接:https://juejin.cn/post/7020343850522640414
35. Kotlin Coroutines 中的异常处理是如何完成的?
详情查看链接:https://johnnyshieh.me/posts/kotlin-coroutine-exception-handling/
36. 在 Kotlin 中如何在 switch 和 when 之间进行选择?
每当我们想要处理许多 if-else 条件时,我们通常会使用 switch-case 语句。但是 Kotlin 提供了一个更简洁的选项,即在 Kotlin 中,我们可以使用 when 来代替 switch。并且,何时可以用作:
表达
任意条件表达式
没有争论
有两个或多个选择
例如:
when(number) {
1 -> println("One")
2, 3 -> println("Two or Three")
4 -> println("Four")
else -> println("Number is not between 1 and 4")
}
37. Kotlin 中的 open 关键字是做什么用的?
默认情况下,类和函数在 Kotlin 中是最终的。因此,您不能继承类或覆盖函数。为此,您需要在类和函数之前使用 open 关键字。例如:
38. 什么是 lambdas 表达式?
Lambdas 表达式是可以被视为值的匿名函数,即我们可以将 lambdas 表达式作为参数传递给函数返回它们,或者做任何其他我们可以对普通对象做的事情。例如:
val add : (Int, Int) -> Int = { a, b -> a + b }
val result = add(9, 10)
39. Kotlin 中的高阶函数是什么?
高阶函数是将函数作为参数或返回函数的函数。例如,函数可以将函数作为参数。
fun passMeFunction(abc: () -> Unit) {
// I can take function
// do something here
// execute the function
abc()
}
例如,一个函数可以返回另一个函数。
fun add(a: Int, b: Int): Int {
return a + b
}
而且,我们有一个函数returnMeAddFunction,它接受零个参数并返回一个((Int, Int) -> Int)类型的函数。
fun returnMeAddFunction(): ((Int, Int) -> Int) {
// can do something and return function as well
// returning function
return ::add
}
而要调用上述函数,我们可以这样做:
val add = returnMeAddFunction()
val result = add(2, 2)
40. Kotlin 中的扩展函数是什么?
扩展函数就像附加到 Kotlin 中的任何类的扩展属性。通过使用扩展函数,即使不继承该类,您也可以向现有类添加一些方法或功能。例如:假设我们有视图,我们需要在其中使用视图的可见性。因此,我们可以为视图创建一个扩展函数,例如,
fun View.show() {
this.visibility = View.VISIBLE
}
fun View.hide() {
this.visibility = View.GONE
}
为了使用它,我们使用,比如,
toolbar.hide()
41. Kotlin 中的中缀函数是什么?
中缀函数用于在不使用任何括号或括号的情况下调用该函数。您需要使用中缀关键字才能使用中缀功能。
class Operations {
var x = 10;
infix fun minus(num: Int) {
this.x = this.x - num
}
}
fun main() {
val opr = Operations()
opr minus 8
print(opr.x)
}
42. Kotlin 中的内联函数是什么?
内联函数指示编译器在代码中使用该函数的任何位置插入完整的函数体。要使用 Inline 函数,您只需在函数声明的开头添加一个 inline 关键字即可。
43. Kotlin 中的 noinline 是什么?
在使用内联函数并希望传递一些 lambda 函数而不是所有 lambda 函数作为内联函数时,您可以明确告诉编译器它不应该内联哪个 lambda。
inline fun doSomethingElse(abc: () -> Unit, noinline xyz: () -> Unit) {
abc()
xyz()
}
44. Kotlin 中的具体化类型是什么?
当您使用泛型的概念将某个类作为参数传递给某个函数并且您需要访问该类的类型时,您需要使用 Kotlin 中的 reified 关键字。
例如:
inline fun genericsExample(value: T) {
println(value)
println("Type of T: ${T::class.java}")
}
fun main() {
genericsExample("Learning Generics!")
genericsExample(100)
}
45. Kotlin 中的运算符重载是什么?
在 Kotlin 中,我们可以使用相同的运算符来执行各种任务,这称为运算符重载。为此,我们需要在函数名称之前提供具有固定名称和操作符关键字的成员函数或扩展函数,因为通常情况下,当我们使用某些操作符时,会在内部调用某些函数。例如,如果您正在编写num1+num2,那么它将转换为
num1.plus(num2).
例如:
fun main() {
val bluePen = Pen(inkColor = "Blue")
bluePen.showInkColor()
val blackPen = Pen(inkColor = "Black")
blackPen.showInkColor()
val blueBlackPen = bluePen + blackPen
blueBlackPen.showInkColor()
}
operator fun Pen.plus(otherPen: Pen):Pen{
val ink = "$inkColor, ${otherPen.inkColor}"
return Pen(inkColor = ink)
}
data class Pen(val inkColor:String){
fun showInkColor(){ println(inkColor)}
}
46. 解释在 Kotlin 中 let、run、with 和 apply 的用例。
47. Kotlin 中的 pair 和 Triple 是什么?
Pair 和 Triples 用于分别从函数返回两个和三个值,返回的值可以是相同的数据类型或不同的数据类型。
val pair = Pair("My Age: ", 25)
print(pair.first + pair.second)
48. Kotlin 中的标签是什么?
用 Kotlin 编写的任何表达式都称为标签。例如,如果我们在 Kotlin 代码中有一个for-loop,那么我们可以将该for-loop表达式命名为标签,并将标签名称用于for-loop。
我们可以通过使用标识符后跟@符号来创建标签。例如,name@、loop@、xyz@等。以下是标签的示例:
loop@ for (i in 1..10) {
// some code goes here
}
上述 for 循环的名称是loop.
49. 使用密封类而不是枚举有什么好处?
密封类为我们提供了拥有不同 类型的子类并包含状态的灵活性。这里需要注意的重点是扩展 Sealed 类的子类应该是 Sealed 类的嵌套类,或者应该在与 Sealed 类相同的文件中声明。
50. Kotlin 中的集合是什么?
详情查看链接:https://juejin.cn/post/6844903702403235853
为您的面试准备这 50 个问题,并通过每个问题中的给定链接来更好地了解该主题。
此外,关注公众号获取资料