kotlin学习总结

 

三. Android:Kotlin详细入门学习指南-基础语法(一)
Kotlin的基础语法:

1. kotlin有但是Java没有的特点?
null safety.
Operator overloading.
Coroutines.
Range expressions.
Smart casts.
Companion objects.

java有的但kotlin没有的?
在kotlin中没有三元条件操作符;
kotlin不支持原始数据类型;

1.2,kotlin支持哪种编程类型?
   一种是procedural编程, 另一种是面向对象的编程。

1.3, 在kotlin中如何处理null异常?
    使用elvis操作符来处理null异常。

1.4, 解释一下kotlin中数据类的作用。
    数据类包含基本的数据类型, 它不包含任何功能函数。

1.5 为什么kotlin跟Java具有互相的操作性?
因为这两门语言,对于jvm来说没有区别。它们都是编译成byte code, 然后在jvm上运行的。

kotlin对标准的Java库和类提供额外的功能吗?
   kotlin程序是跑在标准的Java虚拟机上的。所以kotlin跟Java在这一层级几乎没有区别。Java代码还可以直接在kotlin程序中使用。

2,在kotlin中如何比较两个字符串?
第1种方法你可以用双等号来比较两个字符串。
第2种方法用String.compareTo,这个扩展函数来比较两个字符串。

2.1 在Kotlin泛型中,*和Any的区别
List<*> 更够包含任何类型,但只有该擦除后的类型
List<Any>可以包含任何类型。

2.2 如何在Kotlin中带值初始化数组?
 val numbers: IntArray = intArrayOf(10, 20, 30, 40, 50);

如下数组是什么类型?
val arr = arrayOf(1, 2, 3); --> Array<Int>

2.3 List和Array类型区别
最主要不同是Array固定大小, (Mutable)List可以动态调整大小。 此外Array是可变的,List不可变。
IntArray 和Array<Int> 可以相互交换么?
不能, Array<Int> = Integer[], IntArray = int[] , 中间要经过装箱拆箱。

2.4.什么时候用kotlin内联函数,什么时候不要用?
传入函数类型参数且函数相对来说比较短时,推荐使用内联函数。 当函数比较长且没有使用内联函数。

2.5 解释一下extension函数?
   extension函数用来对class的扩展,而不需要从class进行派生。

说一下kotlin中对Java.io.file的的扩展方法。
bufferedReader.
readBytes.
readText
forEachLine
readLines

2.6 什么是lateinit 和什么时候使用它? 
如不想在构造函数初始化一个变量且你能保证在使用它之前初始化,可以声明为lateinit 变量。 Lateinit不支持原始类型 例如 Int,Long
一些及其实用的案例:
1. Andorid在声明周期实例化的变量
2. 用Dagger 去依赖注入
3. 单元测试的装配, 在@Before函数中初始化的变量
4. Spring Boot注解(@Autowired)

3,说一下kotlin类的缺省行为。
    kotlin类缺省是final的。因为kotlin支持多重类继承。开放类的代价要比final类高很多。

3.1,在kotlin中有多少构造函数?
   有两种,一种是primary构造函数,一种是secondary构造函数。

3.1  Lazy和layinit的区别?
两者都延迟属性的初始。 lateinit 是用于var的修饰符, 可以用于晚点来进行赋值。 Lazy更像一个方法或者一个lambda表达式,只用于val。 在需要时被创建。

什么时候使用lateinit而不是lazy initialization?
  1. 属性是可变的 , 如果不是只初始化一次

如何创建单例?
可用object关键字。 Object不能有构造函数,但可以使用init 块

3.2 Kotlin中伴随体的目的?
不支持static成员,所以用伴随体来放静态成员函数和变量及常量。

为什么kotlin中没有static keyword?
Kotlin的理念是一切皆对象, static由伴随体取代。 伴随体且支持继承,实现接口。

3.3.如何创建空构造函数
第一种方式 构造函数的默认参数
另一种方式 次要构造函数

Kotlin让类的默认可见修饰符为final的动机是什么? 你是否同意?
1. kotlin支持多继承,默认定义为final可以节省开销
2. 类设计原则中,更推荐用合成组合来取代继承。Kotlin用final来默认修饰类。强制使用的人在使用继承时进行进一步的考虑,是否能用其他方式实现。

3.4  kotlin中的抽象有什么作用?
  抽象是面向对象编程中最重要的概念。抽象类特点是,你知道这个类会有什么功能,但是你不知道它具体如何实现这些功能和实现哪些功能。

二.Kotlin的基本用法

Kotlin是什么
Kotlin是Android开发的一级编程语言(Google官方认证);
由JetBrains公司在2010年推出 & 开源,与Java语言互通 & 具备多种Java尚不支持的新特性;
Android Studio3.0后的版本支持Kotlin;

优点
码更少、可读性更强 - 花更少的时间来编写代码与理解他人的代码
成熟的语言与环境 - 自 2011 年创建以来,Kotlin 不仅通过语言而且通过强大的工具在整个生态系统中不断发展。 现在,它已无缝集成到 Android Studio 中, 并被许多公司积极用于开发 Android 应用程序。
Android Jetpack 与其他库中的Kotlin 支持- KTX 扩展 为现有的 Android 库添加了 Kotlin 语言特性,如协程、扩展函数、lambdas 与命名参数。
与 Java 的互操作性 - 可以在应用程序中将 Kotlin 与 Java 编程语言一起使用, 而无需将所有代码迁移到 Kotlin。
支持多平台开发 - 不仅可以使用 Kotlin 开发 Android,还可以开发 iOS、后端与 Web 应用程序。 享受在平台之间共享公共代码的好处。
代码安全 - 更少的代码与更好的可读性导致更少的错误。Kotlin 编译器检测这些剩余的错误,从而使代码安全。
易学易用 - Kotlin 非常易于学习,尤其是对于 Java 开发人员而言。
大社区 - Kotlin 得到了社区的大力支持与许多贡献,该社区在全世界范围内都在增长。 根据 Google 的说法,Play 商店前1000个应用中有60%以上使用 Kotlin。

使用
1、点击Android Studio settings -> Plugins -> 搜索Kotlin Languages插件
2、在根目录的build.gradle中加入
buildscript {
ext.kotlin_version = '1.3.61'
repositories {
 mavenCentral()
}

dependencies {
 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
3、在app/build.gradle中引入
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
buildscript {
ext.kotlin_version = '1.3.61'
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

1.基本语法:
定义包名 - 在源文件的开头定义包名:包名不必和文件夹路径一致:源文件可以放在任意位置。

定义函数:

有返回值: 定义一个函数接受两个 int 型参数,返回值为 int
fun sum(a: Int , b: Int) : Int{
  return a + b
}

fun main(args: Array<String>) {
print("sum of 3 and 5 is ")
println(sum(3, 5))
}
该函数只有一个表达式函数体以及一个自推导型的返回值:

fun sum(a: Int, b: Int) = a + b
fun main(args: Array<String>) {
    println("sum of 19 and 23 is ${sum(19, 23)}")
}
无返回值:返回一个没有意义的值Unit(可省略):

fun printSum(a: Int, b: Int): Unit {
  println("sum of $a and $b is ${a + b}")
}
fun main(args: Array<String>) {
   printSum(-1, 8)
}

2.定义局部变量:
声明常量:

fun main(args: Array<String>) {
val a: Int = 1 // 立即初始化
val b = 2 // 推导出Int型
val c: Int // 当没有初始化值时必须声明类型
c = 3 // 赋值
println("a = $a, b = $b, c = $c")
}
变量:

fun main(args: Array<String>) {
var x = 5 // 推导出Int类型
  x += 1 println("x = $x")
}

注释:
与 java 和 javaScript 一样,Kotlin 支持单行注释和块注释。

// 单行注释
/* 哈哈哈哈 这是块注释 */
与 java 不同的是 Kotlin 的 块注释可以级联。
使用字符串模板
fun main(args: Array<String>) {
var a = 1 // 使用变量名作为模板:
val s1 = "a is $a" a = 2 // 使用表达式作为模板:
val s2 = "${s1.replace("is", "was")}, but now is $a" println(s2)
}
使用条件表达式:

fun maxOf(a: Int, b: Int): Int {
if (a > b) {
return a
} else {
return b
}
}
fun main(args: Array<String>) {
  println("max of 0 and 42 is ${maxOf(0, 42)}")
}
把if当表达式:
fun maxOf(a: Int, b: Int) = if (a > b) a else b
fun main(args: Array<String>) {
   println("max of 0 and 42 is ${maxOf(0, 42)}")
}

使用可空变量以及空值检查:
当空值可能出现时应该明确指出该引用可空。

下面的函数是当 str 中不包含整数时返回空:
fun parseInt(str : String): Int?{ //... }
使用值检查并自动转换
使用 is 操作符检查一个表达式是否是某个类型的实例。如果对不可变的局部变量或 属性进行过了类型检查,就没有必要明确转换:

fun getStringLength(obj: Any): Int? {
if (obj is String) {
// obj 将会在这个分支中自动转换为 String 类型 return obj.length }
// obj 在种类检查外仍然是 Any 类型 return null
}

使用循环:
fun main(args: Array<String>) {
 val items = listOf("apple", "banana", "kiwi")
 for (item in items) {
      println(item)
 }

// 或

 for(index in 0..mutableList.size-1){
      println(mutableList[index])
 }

}
或者这样:
fun main(args: Array<String>) {
val items = listOf("apple", "banana", "kiwi")
 for (index in items.indices) {
      println("item at $index is ${items[index]}")
 }
}
使用 while 循环
fun main(args: Array<String>) {
val items = listOf("apple", "banana", "kiwi")
var index = 0 while (index < items.size) {
println("item at $index is ${items[index]}")
index++
}
}
使用 when 表达式
fun describe(obj: Any): String =
when (obj) {
1 -> "One"
"Hello" ->"Greeting"
is Long -> "Long"
!is String -> "Not a string"
else -> "Unknown"
}
fun main(args: Array<String>) {
println(describe(1)) println(describe("Hello"))
println(describe(1000L))
println(describe(2))
println(describe("other"))
}
使用ranges
使用 in 操作符检查数值是否在某个范围内:
fun main(args: Array<String>) {
val x = 10
val y = 9
if (x in 1..y+1) {
println("fits in range")
}
}
检查数值是否在范围外:
if (-1 !in 0..list.lastIndex) {
println("-1 is out of range")
}
使用步进
for (x in 1..10 step 2)
for (x in 9 downTo 0 step 3)

使用集合:
对一个集合进行迭代
fun main(args: Array<String>) {
val items = listOf("apple", "banana", "kiwi")
for (item in items) {
println(item)
}
}
使用 in 操作符检查集合中是否包含某个对象
fun main(args: Array<String>) {
val items = setOf("apple", "banana", "kiwi")
when {
"orange" in items -> println("juicy")
"apple" in items -> println("apple is fine too")
}
}
使用lambda表达式过滤和映射集合
fun main(args: Array<String>) {
val fruits = listOf("banana", "avocado", "apple", "kiwi")
fruits
.filter { it.startsWith("a") }
.sortedBy { it }
.map { it.toUpperCase() }
.forEach { println(it)
}
习惯用语
创建DTOs(POJOs/POCOs) 数据类
相当于java的Bean,
data class Customer(val name: String, val email: String)
给 Customer 类提供如下方法
-为所有属性添加 getters ,如果为 var 类型同时添加 setters -- equals() - - haseCode() -- toString() -- copy()

函数默认值
fun foo(a: Int = 0, b: String = "") {...}
过滤 list

val positives = list.filter { x -> x >0 }
或者更短:
val positives = list.filter { it > 0 }
字符串插值

println("Name $name")
实例检查
when (x) {
is Foo -> ...
is Bar -> ...
else -> ...
}

遍历 map/list
for ((k, v) in map) {
   print("$k -> $v")
}
k,v 可以随便命名
使用 ranges
for (i in 1..100) { ... } // 闭区间: 包括100
for (i in 1 until 100) { ... } // 半开区间: 不包括100
for (x in 2..10 step 2) { ... }
for (x in 10 downTo 1) { ... }
if (x in 1..10) { ... }
for (i in 1..100) { ... }
for (i in 2..10) { ... }

只读 list:

val list = listOf("a", "b", "c")

只读map:
val map = mapOf("a" to 1, "b" to 2, "c" to 3)
访问 map
println(map["key"])
map["key"] = value

懒属性(延迟加载):

val p: String by lazy { // 生成string的值 }

扩展函数:
fun String.spcaceToCamelCase() { ... }
"Convert this to camelcase".spcaceToCamelCase()
创建单例模式:
object Resource {
    val name = "Name"
}
如果不为空则... 的简写:

val files = File("Test").listFiles()
println(files?.size)

如果不为空...否则... 的简写:
val files = File("test").listFiles()
println(files?.size ?: "empty")

如果声明为空执行某操作?
val data = ...
val email = data["email"] ?: throw IllegalStateException("Email is missing!")

如果不为空执行某操作?
val date = ...
data?.let{ ...//如果不为空执行该语句块 }

 

返回 when 判断

fun transform(color: String): Int {
return when(color) {
"Red" -> 0 "Green" -> 1
"Blue" -> 2
else -> throw IllegalArgumentException("Invalid color pa ram value")
}
}

try-catch 表达式

f```un test() {
val result = try {
count()
}catch (e: ArithmeticException) {
throw IllegaStateException(e)
}//处理 result
}

if 表达式
fun foo(param: Int){
val result = if (param == 1) {
"one"
} else if (param == 2) {
"two"
} else {
"three"
}
}

需要泛型信息的泛型函数的方便形式
// public final class Gson {
// ...
// public <T> T fromJson(JsonElement json, Class<T> classOfT ) throws JsonSyntaxException {
// ... inline
fun <reified T: Any> Gson.fromJson(json): T = this.fromJs on(json, T::class.java)

命名风格
如有疑惑,默认为Java编码约定,比如:
使用骆

驼命名法(在命名中避免下划线)
类型名称首字母大写
方法和属性首字母小写
缩进用四个空格
public 方法要写说明文档,这样它就可以出现在 Kotllin Doc 中

冒号:
在冒号区分类型和父类型中要有空格,在实例和类型之间是没有空格的:
interface Foo<out T : Any> : Bar {
fun foo(a: Int): T
}

Lambdas:
在 Lambdas 表达式中,大括号与表达式间要有空格,箭头与参数和函数体间要有 空格。尽可能的把 lambda 放在括号外面传入

list.filter { it > 10 }.map { element -> element * 2 }
在使用简短而非嵌套的lambda中,建议使用 it 而不是显式地声明参数。在使用 参数的嵌套lambda中,参数应该总是显式声明

类声明格式
参数比较少的类可以用一行表示:

class Person(id: Int, name: String)
具有较多的参数的类应该格式化成每个构造函数的参数都位于与缩进的单独行中。 此外,结束括号应该在新行上。如果我们使用继承,那么超类构造函数调用或实现 的接口列表应该位于与括号相同的行中
class Person(
id: Int,
name: String,
surname: String
) : Human(id, name) {
// ...
}

对于多个接口,应该首先定位超类构造函数调用,然后每个接口应该位于不同的行 中
class Person(
id: Int,
name: String,
surname: String
) : Human(id, name),
KotlinMaker { // ...
}

构造函数参数可以使用常规缩进或连续缩进(双倍正常缩进)。
Unit
如果函数返回 Unit ,返回类型应该省略:
fun foo() { // ": Unit"被省略了 }

函数 vs 属性
在某些情况下,没有参数的函数可以与只读属性互换。尽管语义是相似的,但是有 一些风格上的约定在什么时候更偏向于另一个。
在下面的情况下,更偏向于属性而不是一个函数:

不需要抛出异常 -- 拥有O(1)复杂度 -- 低消耗的计算(或首次运行结果会被缓 存) -- 返回与调用相同的结果。

一. kotlin面试第一部分

1.Kotlin的入口? main函数
函数如何声明? 为什么kotlin函数被称为顶级函数 ?
fun sumOf(a:int, b:Int):Int{ return a+b};
kotlin中的函数能在kotlin根文件中声明

2.这段代码干了什么?
bar {
   System.out.println("Guru99!")
}
该代码传入了一个lambda表达式函数给函数 bar(),这个函数打印 “”Guru99!”。

3.提供一个内联类有用的实际例子
主要用于类型封装, 减少风险,给你简单的,安全的封装器而不引入额外的堆内存分配。
inline fun inlined(block: () -> Unit) {
println("before")
block()
println("after")
}
inlined {
println("do something here")
}
// No Function object instance will be created, instead, the code around the
// invocation of block inside the inlined function will be copied
// to the call site
System.out.println("before");
System.out.println("do something here");
System.out.println("after");

4.Kotlin 支持field 用于干什么?
Kotlin中的类没有字段, 然而,使用自定义访问器的有些时候需要用到支持字段:如下
var selectedColor: Int = someDefaultValue
get() = field
set(value) {
 field = value
}

5.怎么为默认数据类重写getter
data class Test(val value: Int)
我该怎么重写它 让它返回0 如果值是负的
1.不要使用数据类型,用普通类
class Test(value: Int) {
val value: Int = value
get() = if (field < 0) 0 else field
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Test) return false
return true
}
override fun hashCode(): Int {
  return javaClass.hashCode()
}
}
2.创造一个安全的属性
data class Test(val value: Int) {
    val safeValue: Int
    get() = if (value < 0) 0 else value
}

6.Kotlin中的解构声明是什么? 用个例子来解释
解构声明是一种从objects/arrays 灵活的给多个变量赋予值的方式
1.png
Inline函数和Infix函数的区别? 每个给个例子。
内联函数通过组织对象给匿名函数/lambda表达式调用分配空间来节省内存。 相反,它提供在运行时调用它的函数提供函数体。 这可能轻微的增加字节码但是节省一些内存。

插入函数 用于调用没有括号和方括号的函数。这样做代码看起来更像自然语言。
2.png

7. Fold和reduce的基本区别? 且分别什么时候使用他们?
Fold接收一个初始值 listOf(1,2,3).fold(0){ sum, element -> sum + element }
第一次调用lambda将会是 0+1
Reduce不接收初始值,相反从集合的第一个元素开始

8. 如何在Kotlin中实现 建造者模式?
private constructor(builder: Builder) : this(builder.model, builder.year)
class Builder {
var model: String? = null
private set
var year: Int = 0
private set
fun model(model: String) = apply { this.model = model }
fun year(year: Int) = apply { this.year = year }
fun build() = Car(this)
}

9.Reified 关键字如何在kotlin 中工作?
  Reified关键字主要用在泛型当中

10.Apply函数如何在Kotlin中使用?
  创建一个对象且对这个对象进行初始化。

8. SAM 转换是什么?
SAM 表示单个抽象函数。 SAM-type 指的是像Runnable,Callable的接口。当从kotlin中调用java函数,只要传入的满足单一的非默认函数的接口,可以转换成lambda表达式

7, kotlin中的null safety是什么意思?
  null safety的特性是为了去除null pointer exception在实时运行中的出现风险。它也用来区分空引用和非空引用。

6, 什么是range操作符?
   Range操作符用来遍历一个范围。用两个点来表示的。
  for(i in 1..15)
  print(i)

5, 在kotlin中定义一个volatile变量。
   Volatile var x:Long?=null

4, 下面这段代码是干什么用的?
bar{
    System.out.println("haha")
}
bar作为一个函数,正在接收一个表达式为参数,这个表达式用来打印一行字符串。

3, 我们能把Java代码转成kotlin代码吗?
是的,我们可以用jetbrains ide把Java代码转成kotlin,也可以用Android studio转。

2, kotlin允许macros吗?   不允许。kotlin不支持宏。

1,什么是kotlin?
  kotlin是静态类型的编程语言,运行于jvm之上。
   kotlin是由jetbrains开发的。
 为什么我们应该从Java转到kotlin?
首先,kotlin比Java要简单。它去除了很多Java里面的冗余代码。kotlin提供了很多Java不具有的特性。

说一下使用kotlin的三大好处。
kotlin比较容易学,因为它跟Java很接近。
kotlin是功能性编程语言,是基于jvm上的。
kotlin的代码更易读,更容易理解。

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