记录一下与 java 相比的一些根底重要的点
1. 基础知识
1.1 根本类型
kotlin 中没有 java 根本类型的 int、float、double 等,所有货色都是对象,这与 java 相似。然而 kotlin 对数字没有隐式拓宽转换,须要显示转换;数字字面量不反对八进制。
1.2 包与导入
应用 import 关键字,性能上与 java 差不多。import 不限于导入类,还能够导入申明如枚举常量。不同的是 没有相似 import static 的性能。
1.3 控制流
应用 if、when、for、while
when 取代了 switch 性能,然而比 switch 弱小,能够多条件一起,逗号分隔
when (x) {0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
能够应用任意表达式,而不只是常量;能够检测一个值是否在一个区间
when (x) {in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
for/while 的应用跟 java 有点相似,for 循环能够对迭代器对象进行遍历,与 in 应用。
1.4 返回和跳转
return、continue、break 与 java 的性能一样,加了标签性能。kotlin 的表达式都能够用标签(Label)来标记。标签 = 标识符 +@,性能是记录地址,来跳转到相应地位。
1.5 类与对象
1.5.1 类和继承
跟 java 一样应用 class 关键字。kotlin 的一个能够有一个主构造函数以及一个或者多个次构造函数。语法如下:
lass Person constructor(firstName: String) {...}
如果主结构器没有注解或者可见性修饰符,能够省略 constructor 关键字
对于类属性的初始化,能够在 init 关键字的初始化块中,也能够在类属性初始化器初始化。主构造函数的参数能够在初始化块中应用。
1.5.2 属性和字段
类属性,var 示意可变,val 示意只读,只读属性不容许 setter。属性能够自定义 getter/setter 实现,如下:
val isEmpty: Boolean
get() = this.size == 0
属性类型如果能够从初始化器推断进去(getter 返回失去),能够省略。
1.5.3 接口
kotlin 的接口作用跟 java 相似,蕴含形象办法的申明也能够蕴含实现。跟抽象类不同的是,接口不能保留状态。实现接口方式如下:
class Main : MyInterface {override fun run() {// 办法体}
}
针对实现多个接口,笼罩抵触的状况:
interface A {fun run() {print("A run") }
fun drink()}
interface B {fun run() {print("B run") }
fun eat() { print("B eat") }
}
class C : A {override fun run() {print("C run") }
}
class D : A, B {override fun run() {super<A>.run()
super<B>.run()}
override fun eat() {super<B>.eat()
}
}
须要指明如何实现继承的接口办法。
1.5.4 可见修饰符
相比 java,kotlin 在 java 罕用的 public、protected、private 中,加了一个 internal。函数、属性和类、对象、接口都能够在顶层申明。
对于包内:
可见修饰符 阐明
public 如果不指定任何可见修饰符,默认为 public
private 在申明的文件内可见
protected 不适用于顶层阐明
internal 在雷同模块内可见,模块就是一个 idea 模块、maven 我的项目、Ant 工作执行编译的一套文件、一个 Gradle 源集。
对于类外部申明的成员:
可见修饰符 阐明
private 在这个类外部可见
protected 以后类以及子类可见
internal 类申明的本模块内可见
public 内部都能够见
kotlin 中外部类不能范文外部类的公有成员。
1.5.5 数据类
数据类不能是形象、凋谢、密封、或者外部的。
数据类的主构函数的参数至多一个。申明如下所示:
data class User(val name: String,
val gender: String,
val age: Int){fun validate(): Boolean {return true}
}
var/val 必须要带上,编译器为了吧主构函数中申明的所有属性,主动生成上面的函数:
- equals()/hashCode()
- toString() : 格局是 User(name=Jacky, gender=Male, age=10)
- componentN() 函数 : 按申明程序对应于所有属性 component1()、component2() …
- copy() 函数
数据类替换一般类的益处,能够节俭代码,省去一些工作:
(1)在构造函数中申明属性 (非数据类特有),除了构造函数,防止所有 getter/setter 代码
(2)euquals() /hashcode()
(3)Copy() 办法,在应用不变对象时能够应用
1.5.6 泛型
kotlin 没有类型通配符。针对泛型,kotlin 有型变,申明处型变与类型投影。
(1)申明处型变
out 修饰符:
interface Source<out T> {fun nextT(): T
}
fun demo(strs: Source<String>) {val objects: Source<Any> = strs //T 是一个 out- 参数}
in 润饰符号:
interface Comparable<in T> {operator fun compareTo(other: T): Int
}
fun demo(x: Comparable<Number>) {x.compareTo(1.0) // 1.0 领有类型 Double,是 Number 的子类型
// 能够将 x 赋给类型为 Comparable<Double> 的变量
val y: Comparable<Double> = x
}
(2)类型投影
与 java 原声类型比拟相似,为了能够平安应用。平安应用是指对泛型类型定义一个类型投射, 要求这个泛型类型的所有的实体实例, 都是这个投射的子类型。
1.5.7 拓展函数
Kotlin 反对拓展函数和拓展属性。
申明一个扩大函数,须要用一个接收者类型即被扩大的类型来作为他的前缀。如为 MutableList<Int> 增加一个 swap 函数:
fun MutableList<Int>.swap(index1: Int, index2: Int) {val tmp = this[index1] // "this" 对应该列表
this[index1] = this[index2]
this[index2] = tmp
}
1.5.8 单例 (Singleton) 与 伴生对象 (companion object)
kotlin 没有动态属性和办法,object 申明的对象能够提供相似单例的性能。
object Student{
val studentId:Int?=null
val username:String?=null
}
对象属性通过对象名拜访。
kotlin 提供伴生对象,应用 companion object 关键字申明,如
class DataProcessor {fun process() {println("Process Data")
}
object FileUtils {
val userHome = "/Users/jack/"
fun getFileContent(file: String): String {
var content = ""
val f = File(file)
f.forEachLine {content = content + it + "\n"}
return content
}
}
companion object StringUtils {fun isEmpty(s: String): Boolean {return s.isEmpty()
}
}
}
一个类只能有一个伴生对象,默认援用名为 Companion。应用这个实现同 java 动态类应用静态方法的性能. 没有制订伴生对象名称时,调用属性或者办法时,Companion 能够省略不写。
伴生对象的初始化是在相应类被加载解析的时候,这个与 java 动态初始化相似。伴生对象的成员很像 java 以及其余语言的动态成员,然而运行时任然是一个对象的实例成员,还能够实现接口,如:
interface BeanFactory<T> {fun create(): T
}
class MyClass {
companion object : BeanFactory<MyClass> {override fun create(): MyClass {println("MyClass Created!")
return MyClass()}
}
}
应用 java 中的动态成员和静态方法还能够应用注解
@jvmField:生成与该属性雷同的动态字段
@JvmStatic: 在单例对象和伴生对象中生成静态方法
1.5.9 委托
(1) 代理模式
代理模式中,两个对象参加解决同一个申请,承受申请的对象将申请委托给另一个对象来解决。代理模式能够用
聚合代替继承。
(2) 委托属性
class DeletgatePropertiesDemo{var content: String by Content()
override fun toString(){return "seewo"}
}
class Content{operator fun getValue(){return "live"}
operator fun setValue(value:String){println("$value")
}
}
应用 by 将属性的 getter、setter 委托给 Content 对象,对象的对应的两个函数,而且函数是操作符函数。
懒加载属性委托:
val synchronizedLazyImpl = lazy({println("seewo 3!")
println("seewo 2!")
println("seewo 1!")
"Hello 1!"
})
val lazyValueSynchronized1: String by synchronizedLazyImpl
println(lazyValueSynchronized1)
println(lazyValueSynchronized1)
val lazyValueSynchronized2: String by lazy {println("seewo 3!")
println("seewo 2!")
println("seewo 1!")
"Hello 2!"
}
println(lazyValueSynchronized2)
println(lazyValueSynchronized2)
2. 其余
2.1 字符串模板
字符串蕴含模板表达式,会进行求值,并将后果合并到字符串中,比拟简洁好用,跟应用 log 库打印日志的时候应用模板相似。如
val i=10
val s="i=$i"
2.2 空平安
kotlin 可能躲避空指针,在调用属性时候平安调用,能够依据如下形式:
(1) 在条件中查看 null, 例如
val l = if (b != null) b.length else -1
(2) 应用平安调用操作符?. 例如:
bob?.department?.head?.name
(3) Elvis 操作符 ?:
val l = b?.length ?: -1
(4) !! 操作符
val l = b!!.length
用过 GitLab 拉取的 kotlin 我的项目看,比拟罕用这种。
2.3 kotlin 汇合
kotlin 汇合辨别可变以及不可变。
kotlin 对 list、set 等是通过库函数创立如:
ListOf()、mutableListOf()、SetOf()。对与 map 操作应用的库命令与 List、Set 相似,然而 map 分多种,有 TreeMap,HashMap。
底层的实现原理与 java 相似。开发中,习惯应用 java 汇合库的,应用 Guava API,通过应用一些罕用 API,提供汇合的创立、应用形式跟 Java 很相似,容易上手。
2.4 异样
kotlin 所有异样类都是 Throwable 类的子类,异样有堆栈回溯信息、起因等信息。次要的应用形式也是 throw 抛异样,用 try-catch 捕捉异样。不同的是 kotlin 没有受检异样。
2.5 协程
1.2 版本的 kotlin 提供的协程机制处于试验阶段,自搭的 kotlin 环境也是 1.2 版本,api 提醒不稳固,不能用于生产环境,1.3 版本官网说提供了稳固的 API。
(1) 协程集体简略了解
程序蕴含主过程,主过程可能蕴含多个线程,线程蕴含多个协程,协程之间能够嵌套。严格来说其实协程能够间接运行在过程中,非肯定依赖线程。然而目前反对协程的语言如 kotlin、Golang、Python 大都基于主线程开启程序的运行。不同语言的协程实现形式大同小异,作用成果雷同。
(2) 协程的利用场景
如遇到线程阻塞工作时,开启协程,能够缩小资源耗费 (协程资源耗费比线程少,次要通过晋升 CPU 利用率,缩小线程间的切换来晋升程序运行效率)
(3) 个性
官网说法简述:
- 可管制: 协程可能被管制的发动子工作
- 轻量级:协程占用资源比线程小
- 语法糖:多任务或多线程切换不应用回调语法