Kotlin知识点

262 阅读9分钟

1.说说Kotlin和Java有什么区别

与Java 100%互通,并具备诸多Java尚不支持的新特性。 1 kotlin语言更加简洁,比如数据类 Data Classes- 在Kotlin中有数据类,它们导致自动生成样板,如equals,hashCode,toString,getter / setter等等

2 kotlin不必明确指定每个变量的类型,系统会自动判断

3 Kotlin的空安全性很好,摆脱NullPointerExceptions。这种类型的系统帮助我们避免空指针异常。

4 Kotlin允许我们扩展现有类的功能,而不继承它们或者使util类

5 Kotlin是功能性的编程语言,Kotlin由许多有用的方法组成,其中包括高阶函数,lambda表达式,运算符重载等功能性编程使得Kotlin在收藏上更加便利

2.递归和迭代的区别

递归指的是函数自身会调用自身,造成嵌套调用,这种方式会在嵌套数过多的情况下,引起程序发生栈内存溢出异常,问题的出现是因为嵌套过多的情况下,栈内存中保存了所有的函数调用栈,且不会回收,当超出极限时,即发生报错

而迭代时,栈内存中的变量会在不需要时就回收,不会因为迭代次数过多,导致使用的内存相应增长的情况.也就不会有递归的问题.

使用递归算法,逻辑会比使用迭代简单.

kotlin中支持尾递归优化,其实现原理是将递归代码自动转化为迭代代码.

类别 优点 缺点
递归 逻辑比较简单, 容易实现 如果递归层级比较深, 易造成栈内存溢出(内存开销比较大)
迭代 内存开销小 抽象出数学模型, 不容易理解, 编写代码较为困难

3.抽象类和接口的区别

抽象类可用于继承,接口用于被实现,单继承,多实现

抽象类指的是事物的本质属性

接口用于表示事物的能力

类别 抽象类 接口
区别1 标识符: abstract 标识符: interface
区别2 反映的是事物的本质 反映的是事物的能力
区别3 只能单继承 可以多继承
区别4 可以没有方法和字段 必须有方法或字段

4.解释一下泛型和泛型擦除

泛型,即“参数化类型”,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

使用泛型好处是让编译器保留参数类型信息,执行类型检查,执行类型转换操作,同时省掉了显式的强制类型转换,保证了这些类型转换的正确性,保证类型安全,并实现了更为通用的算法。

泛型擦除,泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉

在kotlin中可以使用inline+reified组合的方式,提供在运行时获取泛型的能力

fun main(args: Array<String>) {
    val box1 = Box<String>("")
    val box2 = Box<Int>(10)
}
inline fun <reified T> Box(thing: T) {
    val type = T::class
    println(type)
}

5.解释一下委托,以及他的作用

委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。

Kotlin 直接支持委托模式,更加优雅,简洁。Kotlin 通过关键字 by 实现委托。

如:类的委托,即一个类中定义的方法实际是调用另一个类的对象的方法来实现的。

属性委托,指的是一个类的某个属性值不是在类中直接进行定义,而是将其托付给一个代理类,从而实现对该类的属性统一管理。

  • 类委托

    一个类中定义的方法实际上是调用其他另一个类的对象的方法来实现的

  //创建接口
  interface Base {
      fun print()
  }
  //实现接口
  class BaseImp: Base {
      override fun print() {
          println("hello")
      }
  }
  //通过关键字by建立委托类
  class Driver(b:Base):Base by b
  
  fun main(args: Array<String>) {
      Driver(BaseImp()).print()//输出hello
  }
  • 属性委托

    一个类的某个属性值不是在类中直接进行定义,而是将其托付给一个代理类,从而实现对该类的属性统一管理

  // 定义包含属性委托的类
  class Example {
      var p: String by Delegate()
  }
  // 委托的类
  class Delegate {
      operator fun getValue(ref: Any?, property: KProperty<*>): String {
          return "$ref, 这里委托了 ${property.name} 属性"
      }
  
      operator fun setValue(ref: Any?, property: KProperty<*>, value: String) {
          println("$ref${property.name} 属性赋值为 $value")
      }
  }

6.列举一些你经常用到的高阶函数

  1. kotlin中的集合,就提供了很多高阶函数的操作,过滤,分组,排序,重组,去重等等
  2. 定义DSL时,高阶函数是基本组成部分
  3. 平常使用函数式回调
  4. kotlin编写gradle代码时,{}代表的同样是函数类型

7.说明一下接口回调和函数式回调

  1. java使用的接口回调,需要我们为回调定一个接口类,提供用于回调功能的函数,传参时,需要实现这个接口,实际起作用的仅仅是里面实现的函数
  2. kotlin中可以省去定义一个接口包裹函数的步骤,直接将需要的函数传递过去
接口回调
  1. 定义具备某种接口能力的接口
  2. 传递接口对象给另外一个对象
  3. 通过接口对象将数据返回
  4. 在具有能力的对象方法下接收
函数式回调
  1. 传递接口函数给其他类
  2. 其他类再通过传递的接口将数据传回去
  3. 本类通过lambda表达式接收

8.描述一下函数式编程有什么好处

在函数式编程中,由于数据全部都是不可变的,所以没有并发编程的问题,是多线程安全的。可以有效降低程序运行中所产生的副作用,对于快速迭代的项目来说,函数式编程可以实现函数与函数之间的热切换而不用担心数据的问题,因为它是以函数作为最小单位的,只要函数与函数之间的关系正确即可保证结果的正确性。

函数式编程的表达方式更加符合人类日常生活中的语法,代码可读性更强。实现同样的功能函数式编程所需要的代码比面向对象编程要少很多,代码更加简洁明晰。函数式编程广泛运用于科学研究中,因为在科研中对于代码的工程化要求比较低,写起来更加简单,所以使用函数式编程开发的速度比用面向对象要高很多,如果是对开发速度要求较高但是对运行资源要求较低同时对速度要求较低的场景下使用函数式会更加高效。

参考 https://www.cnblogs.com/zhenw/p/6160931.html

1.代码简洁,开发快速

函数式编程大量使用函数,减少了代码的重复,因此程序比较短,开发速度较快。

2.接近自然语言,易于理解

函数式编程的自由度很高,可以写出很接近自然语言的代码。

3.更方便的代码管理

函数式编程不依赖、也不会改变外界的状态,只要给定输入参数,返回的结果必定相同。

4.易于"并发编程"

函数式编程不需要考虑"死锁"(deadlock),因为它不修改变量,所以根本不存在"锁"线程的问题。不必担心一个线程的数据,被另一个线程修改,所以可以很放心地把工作分摊到多个线程,部署"并发编程"(concurrency)。

9.什么是dsl, dsl有什么优点

dsl(Domain specific language)指的是专注于特定问题领域的计算机语言,与GPL不同.特定领域可以是某一个产业,例如保险教育航空医疗,也可以是某一个方法或者技术,例如数据库,html

DSL只是问题解决方案模型的外部封装,这个模型可能是一个API库,也可能是一个完整的框架

没有具体的标准来区分DSL和普通的API,DSL代码更易于理解,不仅对于开发人员而且对于技术含量较低的人员来说也更易于理解。

10.gradle是什么,有什么用处

gradle是一个自动化的构建工具,可以实现用代码编写功能的需求,可用来编译测试,依赖管理,通过DSL自定义拓展任务,总之他是一个很牛逼的构建工具,构建一切可构建的内容

11.task的生命周期

分为扫描时生命周期,和运行时生命周期,定义在doFirst和doLast中.

直接写在task中的代码 在 扫描时生命周期 执行, 顺序由定义时上下顺序决定

而运行时生命周期的代码 会在扫描后执行,而且执行顺序由task之间的依赖顺序决定

12.线程join有什么作用

  • 将线程之间的并行执行变成串行执行
  • 让主线程和新线程按编程顺序执行

13.线程和协程的区别

协程是一种用户态的轻量级线程,协程的调度完全由用户控制。

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.

协程和线程的区别

1 一个线程可以多个协程,一个进程也可以单独拥有多个协程

2 线程进程都是同步机制,而协程则是异步

3 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态

14.描述协程的工作原理

协程通过挂起 耗时的 非阻塞的 可挂起函数,从而使耗时操作不阻塞程序的运行, 在挂起的函数结束挂起后,从线程池中提供空闲的线程去继续执行