kotlin学习总结2

二. kotlin面试第二部
转载:https://www.jianshu.com/p/45866c8415c8

1. kotlin有而java没有的特性
1.空指针安全
2.操作符重载
3.协程
4.Range 表达式
5.智能转换
6.伴随体

kotlin优势?
- Kotlin更安全:如空引用由类型系统控制,你不会再遇到NullPointerException。
- 简洁,可靠,有趣: 如你可用Lambda 表达式;可以减少了很多模版代码;
- 函数式支持;
- 扩展函数;
      Kotlin同C#类似,能够扩展一个类的新功能而无需继承该类或使用像装饰者这样的任何类型的设计模式。Kotlin支持扩展函数和扩展属性。
- Kotlin中没有静态成员;
- ......
与Java交互:
Kotlin可与Java进行100%的互操作,允许在Kotlin应用程序中使用所有现有的 Android 库 ,Kotlin的标准库更多的是对Java库的扩展。
Kotlin的一个主要优点是它的简洁。你用很少的代码就可以实现原来Java写的功能,而你写的代码越少,你犯错误的概率就越小。光这个原因我就比较推荐大家尝试。正如巴菲特所说“投资的秘诀不是如何赢,而是如何比别人少犯错误。”

对比java,kotlin的优势?

空指针安全
自带单例(object)
数据类型toString, hashcode, equals 。 不需要自己写。 Setter和getter也不需要自己写
Kotlin支持扩展函数

Kotlin的缺点:
没有明显意义的关键字, internal, crossinline, expect, reified, sealed, open. 生成很多不一定需要的代码。
java有的而kotlin没有的 :  检查异常,原始类型, 静态成员, 非私有字段, 通配符类型, 三元操作符。

kotlin的目标平台是什么?
为什么kotlin-java的交互是可能的 JVM是ktolin的目标平台。Kotlin百分百可与java交互,因为两者都编译生成字节码。
因此Kotlin能把Java调用,反之亦然。

2.什么是协程?
轻量级线程,创建协程不需要分配新的线程,相反,它使用已经定义好的线程池,智能调度。此外,协程可以挂起和恢复。
Suspending和blocking的区别?
Blocking 意味着在同一线程暂停本函数的调用。此外,如果你在主线程调用阻塞函数,将暂停UI直到阻塞函数执行完。不建议这么做。*
Suspending 不需要阻塞本函数的调用。

什么是协程域(Coroutine Scope),且和协程上下文(Coroutine Context)区别是什么?
1. 协程总是在一些上下文中执行。 协程上下文是一系列元素的集合。最主要的是协程的job
2. 协程域 没有它自己的数据,它只拥有一个协程上下文(CoroutineContext)。

Launch/join 和 async/await 在kotlin协程中的区别是什么?
Launch 和启动线程相似,当有异常从该线程抛出。处理方式与线程中未捕获的异常相似。在stderr打印出错误且让应用程序崩溃。
Join用于等待执行的协程完成,它不传递异常。 然而,一个崩溃的子协程将会取消它的父协程。
Async 用于执行一个协程且可获得一个Deferred 实例。可调用await来得到协程的执行结果。 未捕获的异常被存在Deferred的结果当中。

val job = Job()
val scope = CoroutineScope(job!!)
scope.launch {
  val result = async {
   5 + 10
   }.await()
  Log.e(tag,"result is $result")
}

为什么协程比RxKotlin/RxJava好
1. Kotlin比Rx系列易于理解,subscribeOn ObserveOn 是让人迷惑的。
2. 灵活,且更多控制 。 例如:对于给定计算,你可以控制优先级,是否平行计算,是否锁定资源。
3. 被压处理上,kotlin比Rxjava更容易。

什么是kotlin
Kotlin 是一个运行在JVM上的静态类型的程序语言。它可以使用Java源码或者LLVM编译器编译。
kotlin的开发者是谁?    JetBrains.

为什么kotlin和java是可交互的?
因为它也使用jvm字节码。把它直接编译成字节码有助于实现更快的编译时间且对于jvm而言和java无差异。
Kotlin支持哪几种编程类型?    1.面向过程   2.面向对象
我们能把代码从java迁移到kotlin么?   可以,IDEA提供一个 内置的工具来进行迁移

使用kotlin三个最重要的优势 ?
1.易学,语法与java相似
2.基于jvm的函数式语言,移除了很多样板代码。
3.让代码更易读,更易理解

Kotlin中是否有像java那样的三元操作符?   没有

2. kotlin中数据类的使用?   数据类型持有基础数据类型,不包含任何功能
Kotlin支持宏指令么? 不支持
Kotlin类的默认行为?
      Kotlin中所有的类默认为final. Kotlin支持多继承,Open class比final class造成更多开销
Kotlin是否支持原始数据类型?  不

Kotlin中数据类是什么? 什么使它如此有用? 如何定义?
在java中,创建一个数据类存贮数据,你需要设置变量,getter()和setter(),重写toString(), hash() 和copy()函数。
在kotlin中,只需要在类头增加data关键字,上述所有都被自动生成。

Kotlin中的数据类型?
首要构造函数至少一个参数,所有的构造函数的参数必须标记为var 或者val 。 数据类不能为abstract, open, sealed 或者inner

Kotlin中有多少有效构造函数?
       两类构造函数 1.主要构造函数   2.次级构造函数

什么是kotlin init代码块
init是Kotlin初始化器,它在首要构造函数实例化后被调用。Init块的代码在次级构造函数调用之前调用。即使没有主要构造函数,该函数将被隐性调用。

Kotlin构造函数类型? 区别是什么?如何在类中定义?
首要构造函数- 在类头中定义,不能持有任何逻辑,每个类只有一个首要构造函数。
次要构造函数-定义于类体中。如果存在必须代理给首要构造函数,可以有逻辑。且可有多于一个次要构造函数。

如下的集成结构能否编译?
Class A{} , classB:A(){} 不能,ktolin的默认类是final的,你需要加Open修饰符

Abstraction在kotlin中的用处?
抽象是oop中最重要的概念。 在kotlin, 抽象类当你知道一个类应该有什么功能。但是你不清楚功能怎么实现或 功能能用不同方法实现。

解释扩展函数的使用? 扩展函数有助于扩展类而不需要继承类

  Kotlin提供java.io.File的扩展函数的名字 ?
1.bufferedReader():用于读取一个文件到BufferedReader
2.readBytes():用于读取文件内容到字节数组
3.readText():用于读取文件内容到单个字符串
4.forEachLine():用于一行一行的读取一个文件 5.readLines():用于读取文件中的行到List中。

Kotlin有没有static 关键字? 如何创建static函数?
   没有,创建静态函数可以用伴随体。

3.什么是kotlin中域函数?
Let,Run,With,Apply,also

什么是空安全和可空类型,什么是Elvis操作符 ?
kotlin非常重视空安全。 通过用可空类型(String?, Int?, Float?等)来阻止空指针异常。
Elvis操作符 newStr = str?: "Default Value" , 如果str为空右边的值将被使用。

kotlin如何处理空指针异常?
Elvis操作符,用于处理空指针异常 val l: Int = if (b != null) b.length else -1  可替换为:val num = b?.length ?: -1
空安全在kotlin意味着什么?
空安全特性让kotlin移除了实时出现的空指针异常的风险。区分空引用和非空引用也是可能的。

如何声明变量,且与java有何不同 ?
Kotlin 以val, var 开头,跟可选类型,ktolin用类型引用自动推断类型。

声明的val 和var有何不同?
val变量不可变,和java中final修饰符类似。 Var 可再被赋值,且必须为同类型。

什么是 const?  和val有什么区别?
Val是在运行时被设置, 在val上加一个const 修饰符将会变成编译时常量。 Const不能修饰var,不能用于局部变量

声明一个volatile 变量?   Volatile var x: Long? = null

如何比较两个字符串?
1.== 操作符     2.compoareTo() 扩展函数

== 和 === 的区别?
==比较双方的值是否相等, ===比较双方引用是否相等。

列举出kotlin的可见修饰符, 什么是默认的可见修饰符?
  public, internal, protected, private。public是默认的修饰符

字符串插入在Kotlin中怎么工作。 用一个代码块解释 ?
val name = "Journaldev.com" 

val desc = "$name now has Kotlin Interview Questions too. ${name.length}"  用$在字符串中增加变量,用美元符号+{}来计算表达式  ( 美元符号会转义,所以部分用中文代替)

构造函数中的参数类型是?  默认为val, 除非明确设置成var
Kotlin中是否有new关键字?  如何实例化一个类对象没有, var a = A()

Kotlin switch关键字的被替换是什么关键字?  有何区别?
switch用When替换, default 用else来替换:

var num = 10

when (num) {

0..4 -> print("value is 0")

5 -> print("value is 5")

else -> { print("value is in neither of the above.") } }

什么是Kotlin  !!操作符?
非空断言, 把任何值转换成一个非空类型,如果值为空, 抛出KotlinNullPointerException。

!!操作符 和?.操作符 在打开可空变量时有什么区别? 是否有其他方式安全的打开可空类型 ?
 !!操作符强行打开可空类型。如何返回值是Null,可导致运行时崩溃。 因此!!只用于你确定这个值不会为空。

 ?.是一个Elvis操作符可是安全的调用。 我们可以用lambda表达式 let来安全的调用。

与switch相比,when的优势?
更灵活: 支持数字,字符串,对象,以及range
· fun describe(obj: Any): String =
· when (obj) {
· 1 -> "One"
· "Hello" -> "Greeting"
· is Long -> "Long"
· !is String -> "Not a string"
· else -> "Unknown"
· }

函数返回Unit的目的? 为什么是这个值?  值是什么?
目的与c和java相同。 只有Unit是一个合适的类型,所以可作为泛型参数传递

什么是ranges操作符?
Ranges操作符帮助遍历一个范围。 操作符形式 是(…),例如: for (i in 1..15)

Kotlin能为标准java包或类提供额外的函数 ?
(kotlin程序能像其他java代码那样在jvm上运行。且允许jvm把任何程序编译成字节码。使用java虚拟机是可访问的,因此,kotlin跟java相似。此外,Kotlin应用能用部分java代码构建)能。

一. kotlin面试第一

1. Kotlin 基础
== 和 equal() 相同,=== 比较内存地址。

类型系统:
a1.数值类型:

Kotlin 将基本数据类型和引用型统一为:Byte、Short、Int、Long、Float、Double、Char 和 Boolean。
需注意,类型的统一并不意味着 Kotlin所有的数值类型都是引用类型,大多数情况下,它们在编译后会变成基本数据类型,类型参数会被编译为引用类型。
a2.类型转换: 较小类型并不是较大类型的子类型,较小的类型不能隐式转换为较大的类型。
val b: Byte = 1 // OK, 字面值是静态检测的
val i: Int = b // 错误
val i: Int = b.toInt() // OK

a3.只读集合和可变集合:
只读集合只可读,而可变集合可以增删改差(如List 只读,MutableList 可变)。
注意,只读集合引用指向的集合不一定是不可变的,因为你使用的变量可能是众多指向同一个集合的其中一个。

a4.Array 和 IntArray 的区别:
Array<Int> 相当于引用类型数组 Integer[],IntArray 相当于数值类型数组 int[]。

面向对象?
a1.类修饰符
Kotlin 类 / 方法默认是 final 的,如果想让继承类 / 重写方法,需要在基类 / 基方法添加 open 修饰符。
final:不允许继承或重写
open:允许继承或重写
abstract:抽象类 / 抽象方法

a2.访问修饰符
Java 默认的访问修饰符是 protected,Kotlin默认是 public。
public:所有地方可见
internal:模块中可见,一个模块就是一组编译的 Kotlin 文件
protected:子类中可见(与Java 不同,相同包不可见)
private:类中可见

a3.内部类
Kotlin:默认为静态内部类,如果访问类中的成员方法和属性,需添加 inner称为非静态内部类;
Java: 默认为非静态内部类。

a4.object 与 companion object 的区别
object 有两层语义:静态匿名内部类 + 单例对象
companion object 是伴生对象,一个类只能有一个,代表了类的静态成员(函数 / 属性)

a5.object 单例的原理

a1.顶级成员(函数 & 属性)的原理:
Kotlin 顶级成员本质是Java 静态成员,编译后会自动生成文件名Kt的类,可以使用@Jvm:fileName注解修改自动生成的类名
默认参数的原理: Kotlin 默认参数的本质是将默认值 固化 到调用位置,所以在 Java 中无法直接调用带默认参数的函数,需要在 Kotlin 函数上增加@JvmOverloads注解,指示编译器生成重载方法

a2.解构声明的原理: Kotlin 解构声明可以把一个对象的属性结构为一组变量,所以解构声明的本质是局部变量。
举例:
val (name, price) = Book("Kotlin入门", 66.6f)
println(name)
println(price)
--------------
Kotlin 类需要声明`operator fun componentN()`方法来实现解构功能,否则是不具备解构声明的功能的,例如:
class Book(var name: String, var price: Float) {
operator fun component1(): String { // 解构的第一个变量
return name
}
operator fun component2(): Float { // 解构的第二个变量
return price
}
}
a3.扩展函数的原理:
扩展函数的语义是在不修改类 / 不继承类的情况下,向一个类添加新函数或者新属性。本质是静态函数,静态函数的第一个参数是接收者类型,调用扩展时不会创建适配对象或者任何运行时的额外消耗。在 Java 中,我们只需要像调用普通静态方法那样调用扩展即可。
相关深入文章:《Kotlin | 扩展函数(终于知道为什么 with 用 this,let 用 it)》

a4.委托机制的原理:
Kotlin 委托的语法关键字是 by,其本质上是面向编译器的语法糖,三种委托(类委托、对象委托和局部变量委托)在编译时都会转化为 “无糖语法”。例如类委托:编译器会实现基础接口的所有方法,并直接委托给基础对象来处理。例如对象委托和局部变量委托:在编译时会生成辅助属性(prop$degelate),而属性 / 变量的 getter() 和 setter() 方法只是简单地委托给辅助属性的 getValue() 和 setValue() 处理。相关深入文章:《Kotlin | 委托机制 & 原理 & 应用》

a5.let、with、apply 的区别和应用场景:

a6.中缀函数: 声明 infix 关键字的函数是中缀函数,可以使用中缀表示法调用(忽略点和括号)
中缀函数的要求:
- 1、成员函数或扩展函数
- 2、函数只有一个参数
- 3、不能使用可变参数或默认参数
举例:
infix fun String.吃(fruit: String): String {
return "${this}吃${fruit}"
}
调用: "小明" 吃 "苹果"

 

3. 协程
协程的原理: 使用同步代码编写异步程序
框架: Kotlin-Flow

lambda 表达式?
a.lambda 表达式本质上是 「可以作为值传递的代码块」。在老版本 Java 中,传递代码块需要使用匿名内部类实现,而使用 lambda 表达式甚至连函数声明都不需要,可以直接传递代码块作为函数值。
b.当 lambda 表达式只有一个参数,可以用 it 关键字来引用唯一的实参。
c.lambda 表达式的种类
1、普通 Lambda 表达式:例如: ()->R
2、带接收者对象的 Lambda 表达式:例如 T.()->R
d.lambda 表达式访问局部变量的原理: 在Java 中,匿名内部类访问的局部变量必须是 final 修饰的,否则需要使用数组或对象做一层包装。在 Kotlin 中,lambda 表达式可以直接访问非 final 的局部变量,其原理是提供了一层包装类,修改局部变量本质上是修改包装类中的值。
class Ref<T>(var value:T)

e.lambda 编译优化: 在循环中使用 Java 8 与 Kotlin 中的 lambda 表达式时,会存在编译时优化,编译器会将 lambda 优化为一个 static 变量,除非 lambda 表达式中访问了外部的变量或函数。

f.内联函数的原理: lambda 表达式编译后会变成匿名内部类,至少会生成一个中间对象,当 lambda 表达式被经常调用时,会增大运行开销。使用内联函数可以减少中间对象的开销,因为调用内联函数不会真正调用函数,而是把函数实现固化到函数调用的位置。需要注意:如果函数体太大就不适合使用内联函数了,因为会大幅度增加字节码大小。
h.实化类型参数 reified: 因为泛型擦除的影响,运行期间不清楚类型实参的时机类型,Kotlin 中使用 带实化类型参数的内联函数 可以突破这种限制,实化类型参数在插入到调用位置时会使用类型实参的确切类型代替,因此可以确定实参类型。

在这个函数里,我们传入一个List,企图从中过滤出 T 类型的元素:
Java:
<T> List<T> filter(List list) {
List<T> result = new ArrayList<>();
for (Object e : list) {
if (e instanceof T) { // compiler error
result.add(e);
}
}
return result;
}
---------------------------------------------------
Kotlin:
fun <T> filter(list: List<*>): List<T> {
val result = ArrayList<T>()
for (e in list) {
if (e is T) { // cannot check for instance of erased type: T
result.add(e)
}
}
return result
}
调用:
val list = listOf("", 1, false)
val strList = filter<String>(list)
---------------------------------------------------
内联后:
val result = ArrayList<String>()
for (e in list)
if (e is String) {
result.add(e)
}
}

 在 Android 生态中主要有 C++、Java、Kotlin 三种语言 ,它们不是替换而是互补。
其中,C++ 的语境是算法和高性能,Java 的语境是平台无关和内存管理,
而 Kotlin 则融合了多种语言中的优秀特性,带来了一种更现代化的编程方式。
例如简化异步编程的协程(coroutines),提高代码质量的可空性(nullability),lambda 表达式等;

posted on 2022-03-27 22:31  左手指月  阅读(345)  评论(0编辑  收藏  举报