一、前言
Kotlin的使用与java做参考对比(这两者语言属于兄弟关系)
编译型语音:编译器直接将源代码一次性地编译成计算机可识别的二进制文件,然后计算机直接执行,像c、c++都属于编译型语言。效率高
解释型语言:解释语言有一个解析器,在程序运行时,解释器会一行行地读取我们编写的源代码,然后实时地将这些源代码解析成计算机可识别的二进制数据后再执行,像Java、Python、JavaScript解释型语言。效率较差些
java与Kotlin相互转换、无缝对接原理:首先我们得知道java编译运行机制,初学java时会使用javac把源代码编译成.class二进制文件,该二进制不可被计算机直接执行需要通过虚拟机JVM(Andrid5.0后加ART)解析才能识别执行,这虚拟机就是充当解释器的功能。知道java语言的运行机制之后(虚拟机只解析执行.class文件,虚拟机不管.class怎么生成只要按.class规范生成就行),所以Kotlin的工作原理就是编译生成虚拟机对应规范的.class文件就行。java转Kotlin容易,但Kotlin转java难,因为Kotlin添加了许多新特性比如协程
二、变量
Kotlin对象数据类型 | 数据类型说明(与java相比就是首字母大写) |
---|---|
Int | 长整型 |
Long | 短整型 |
Short | 单精度浮点型 |
Float | 双精度浮点型 |
Double | 布尔值 |
Char | 字符型 |
Byte | 字节型 |
Number | 数字类型 |
Kotlin区分三种变量(与java相比变量名写在前类型写在后,每行代码结束没有分号)
1.val(value的简写)不可变的变量类似于java的final变量。语法 val a:Int =10
2.var(variable的简写)可变的变量
3.lateinit 延迟对象的初始化 private lateinit var person :Person
//判断一个对象是否初始化
if(!::person.isInitialized){
person = Person()
}
三、函数定义
函数语法如下:
fun methodName(param1:Int, param2:String):Int{
return 0
}
语法糖:
1.当一个函数只有"一行代码"时可以不必编写函数体,可直接将唯一的"一行代码"写在函数的尾部,中间用等号链接
fun largerNumber(num1:Int,num2:Int):Int = max(num1,num2)
2.类型推导机制,当函数值返回明确时可直接省略返回值类型
fun largerNumber(num1:Int,num2:Int) = max(num1,num2)
静态方法
有几种表现形式
1.companion object 修饰方法(Kotlin 会为其生成伴生类对象)
class Util{
companion object{
fun doAction(){
println("do action")
}
}
}
2.@JvmStatic注解(只能用于companion object 修饰的方法和单例上,真正意义上的静态方法)
class Util{
companion object{
@JvmStatic
fun doAction(){
println("do action")
}
}
}
3.顶层方法
说明:直接创建一个.kt的文件然后直接在该文件上编写方法就是顶层方法,比如main函数
4.infix函数
定义条件:
1.infix函数不能定义成顶层函数,它必须是某个类的成员函数
2.infix函数必须接受且只能接受一个参数
infix fun<T> Collection<T>.has(element: T) = contains(element)
val list = listof("Apple","Banana","Orange")
if (list has "Banana"){
//处理对应的逻辑
}
四、程序逻辑控制
1.条件语句区分两种:if和when
if:if语句有返回值,每个条件的最后一行代码作为返回值
fun getScore(name:String) = if(name = "Tom"){
80
}else if(name = "Jim"){
70
}else{
0
}
when 语法如下:(类似java的switch)
匹配值 -> {执行逻辑}
fun getScore(name:String) = when(name){
"Tom" -> 80
"Jim" -> 70
else -> 0
}
扩展
fun getScore(name:String) = when{
name.startsWith("Tom") -> 80
name == "Jim" -> 70
else -> 0
}
fun checkNumber(number:Number){
when(number){
is Int -> println("number is Int")
is Double -> println("number is Double")
else -> println("number not support")
}
}
语法糖:
is 相当于java中的 instanceof 关键字
2.循环语句:while与for
Kotlin区间的概念:
val range = 0…10 表示[0,10]
val range = 0 until 10 表示[0,10)
for(i in 0..10 step 1){//step 1 表示循环每次步进为1
println(i)
}
for(i in 0 until 10 step 2){//step 2 表示循环每次步进为2(until 左闭右开[0,10))
println(i)
}
for(i in 10 downTo 1){降序循环 [10,0]
println(i)
}
五、类与对象
Java和Kotlin可见性修饰符
修饰符 | Java | Kotlin |
---|---|---|
public | 所有类可见 | 所有类可见(默认) |
private | 当前类可见 | 当前类可见 |
protected | 当前类、子类、同一包路径下类可见 | 当前类、子类可见 |
default | 同一包路径下类可见(默认) | 无 |
internal | 无 | 同一模块中的类可见 |
类的定义方式:(类中的属性不再需要实现get、set方法Kotlin默认实现,对象的创建不需要使用new关键字)
class Person{ var name = "" var age = 0} //不可继承
open class Person{} //可继承类
data class Person(val name:String,val age:Int) //数据类(模型)
object Sigleton{} //单例类
//匿名类实例使用object关键字
Thread(object:Runnable{
override fun run(){
println("Thread is running")
}
})
interface Person{} //接口——接口实现统一跟类继承一样不需要关键字implements
sealed class Person{}//密封类的定义(用于条件语句when判断,保证考虑到所有分支)
类的继承与构造(继承使用 ‘”:“ 冒号,类与接口继承使用逗号分开)
class student(val no:String,val grade:Int,name:String,age:Int = 7):Person(name,age){
init{
println("初始化参数,类似于java构造函数") //主构造函数初始化
}
constructor(name:String,age:Int):this("",0,name,age){} //次构造函数--次构造函数必须调用主构造函数,这个有点像java中构造函数参数少的调用参数多的构造函数,只是kotlin直接从语法上就限定了
constructor():this("",0){} //次构造函数
}
注意:
1.student类定义中name:String,age:Int是不带有变量类型的,因为它取的是父类Person的类型
2.如果Person类没有主构造函数,继承时是不带括号的
class student:Person{}
3.其实次构造函数用的很少,可以用主构造函数的默认传参方式代替次构造函数,除非次构造函数内部有逻辑处理
六、Lambda编程
1.语法结构:(一小段可以作为参数传递的代码)
{参数名1:参数类型,参数名2:参数类型 -> 函数体(最后一行作为Lambda的返回值)}
2.使用Lambda编程前先认识几种集合的创建(list、set、map)方式
list:几种初始化创建方式
//传统方式不推荐
val list = ArrayList<String>()
list.add("Apple")
list.add("Banana")
list.add("Orange")
//推荐使用
val list = listof("Apple","Banana","Orange") //不可变只读集合
val list = mutableListof("Apple","Banana","Orange")//可变集合
set:几种初始化创建方式
val set = setof("Apple","Banana","Orange")//不可变只读集合
val set = mutableSetof("Apple","Banana","Orange")//可变集合
map:几种初始化创建方式
//传统方式不推荐
val map = HashMap<String,Int>()
map.put("Apple",1)
map["Banana"] = 2//数组下标推荐使用该种方式设置
//推荐使用
val map = mapof("Apple" to 1,"Banana" to 2,"Orange" to 3)//不可变只读集合
val map = mutableMapof("Apple" to 1,"Banana" to 2,"Orange" to 3)//可变集合
集合的函数式API使用
lambda几种函数举例使用
val list = listof("Apple","Banana","Orange")
maxBy函数:求集合中字符长度最长的一个
val maxLengthFruit = list.maxBy({fruit:String->fruit.length})
//对如上表达式进行简化变形
1.Kotlin规定Lambda参数是函数最后一个参数时,可以将Lambda表达式移到函数括号外,变形如下:
val maxLengthFruit = list.maxBy(){fruit:String->fruit.length}
2.Kotlin规定Lambda参数是唯一一个参数时可以将括号省略,变形如下:
val maxLengthFruit = list.maxBy{fruit:String->fruit.length}
3.根据Kotlin类型推导机制,所以可以不必声明变量类型,变形如下:
val maxLengthFruit = list.maxBy{fruit->fruit.length}
4.Kotlin规定Lambda表达式只有一个参数时,可以不必声明参数名,可以用it代替,变形如下:
val maxLengthFruit = list.maxBy{it.length}
map函数:把集合中的对象转变成另一种对象
val newList = list.map{it.toUpperCase()}
filter函数:过滤集合中满足条件的对象
val newList = list.filter{it.lenth <= 5}
any函数:判断集合中是否至少存在一个元素满足指定的条件
val newList = list.any{it.lenth <= 5} //true
all函数:判断集合中是否所有元素都满足指定的条件
val newList = list.all{it.lenth <= 5} //false
Java函数式API使用
限制条件:必须是Java单抽象方法接口参数,比如如下接口
public interface Runnable{void run();}//只有一个run()方法
public interface OnClickListener{void onClick(View v);}//只有一个onClick()方法
//Lambda简化
Thread{
println("Thread is running")
}.start()
btn.setOnClickListener{}
七、空指针
1.可空类型: val student:Student?
2.判空辅助工具:
**?. ** 表示为空时不执行,不为空时执行
if (a != null){
a.doSomething()
}
//简写
a?.doSomething()
?: 表示左边表达式不为空返回左边表达式,否则返回右边表达式
val c = a ?: b
!! 非空断言工具
val upperCase = content!!.toUpperCase()//告诉编译器我非常明确这里对象不会为空(这是一种风险)
八、标准函数
let:语法如下
obj.let{obj->
//doSomething
}
说明:obj对象调用let函数,并且把obj对象本身作为参数传递给Lambda表达式中
fun doStudy(study:Study?){
study?.doSomething1()
study?.doSomething2()
}
以上函数最终会编译成如下:
fun doStudy(study:Study?){
if(study != null){study.doSomething1()}
if(study != null){study.doSomething2()}
}
//顾用let优化
fun doStudy(study:Study?){
study?.let{
it.doSomething1()
it.doSomething2()
}
}
with:语法如下
val result = with(obj){
//这里是obj的上下文
"value" //with函数的返回值
}
说明:
with函数接受两个参数,第一个参数可以是任意类型的对象,第二个参数是一个Lambda表达式。Lambda表达式中提供第一个参数的上下文,并且最后一行代码作为返回值
val list = listof("Apple","Banana","Orange")
val result = with(StringBuilder()){
append("start eating fruit.\n")
for(fruit in list){
append(fruit).append("\n")
}
append("Ate all fruit")
toString()
}
println(result)
run:语法如下
val result = obj.run{
//这里是obj的上下文
"value" //run函数的返回值
}
说明:
某个对象上调用run函数,run函数接受一个Lambda参数,并且会在Lambda表达式中提供调用的上下文,with函数类似
val list = listof("Apple","Banana","Orange")
val result = StringBuilder().run{
append("start eating fruit.\n")
for(fruit in list){
append(fruit).append("\n")
}
append("Ate all fruit")
toString()
}
println(result)
apply:语法如下
val result = obj.apply{
//这里是obj的上下文
}
//result == obj
说明:
在某个对象上调用apply函数,apply函数接受一个Lambda参数,并且会在Lambda表达式中提供调用的上下文,run函数类似,但没有返回值
//举例1:
val list = listof("Apple","Banana","Orange")
val result = StringBuilder().apply{
append("start eating fruit.\n")
for(fruit in list){
append(fruit).append("\n")
}
append("Ate all fruit")
}
println(result.toString())
//举例2:
val intent = Intent(content,FirstActivity::class.java).apply{
putExtra("param1","data1")
putExtra("param2","data2")
}
content.startActivity(intent)
repeat:语法如下
repeat(n){
//重复操作的逻辑
}
说明:
重复n遍的repeat()的函数
val builder = StringBuilder()
repeat(3){
builder.append("abc")
}
println(builder.toString())//abcabcabc