改不完的 Bug,写不完的矫情。公众号 小木箱成长营 现在专注移动基础平台开发 ,涵盖音视频, APM和信息安全等各个知识领域;只做全网最 Geek 的公众号,欢迎您的关注!精彩内容不容错过~
一. kotlin简介
Kotlin 拥有强大的生态,因为Kotlin是一门跑在Java虚拟机上的函数式语言,完全符合JVM的设计规范,如: 类型擦除,装箱和拆箱等等。所以也可以像Java一样支持 Android原生环境开发,服务端,甚至大前端方向。那么Kotlin和Java有什么共同点呢?
二. kotlin和java8的相同点
kotlin和java8的相同点我总结了三个,第一个是: 它们都是面向对象和函数式编程语言,第二个是: 它们都是强类型静态语言,最后一个就是它们都符合JVM设计规范
三. kotlin和java8的不同点
kotlin和java8的不同挺多的,我简单的归纳了一下:
- Kotlin可以用操作符简洁的判空
- Kotlin 不需要 findViewById
- Kotlin 默认给你写好 setter 和 getter方法了
- Kotlin 去掉了 static 关键字
- Kotlin 进行 自动强制类型转换
- Kotlin 省去了 类型推断
- Kotlin 不支持类型检查
- Kotlin 有协程支持
四. kotlin 和 java 互转
4.1 kotlin 转 java
4.2 java 转 kotlin
查看Kotlin字节码
五. Kotlin 基础语法
5.1 kotlin方法
5.1.1 kotlin方法声明
Kotlin 定义方式比较简单,括号中是参数,格式: "函数名(参数名称: 参数): 返回类型",返回类型定义在括号外 如:T
fun <T> reflectField(instance: Any?, name: String): T? { if (instance == null) return null try { val field = instance.javaClass.getDeclaredField(name) field.isAccessible = true return field.get(instance) as T } catch (e: Exception) { e.printStackTrace() } return null }
5.1.2 kotlin方法调用
5.1.3 kotlin方法自动传参
Kotlin 可以在 构造方法或者相关函数大括号里面设置默认参数,这样传参就可以使用默认参数了,我们具体看看怎么使用的吧
第二个参数可以省略,此时会使用默认值
不省略时跟Java无异
5.1.4 kotlin named argument
named argument 的中文含义是 可以根据 参数名 进行传递参数,传参顺序不需要严格按照函数定义顺序,这样就可以避免参数误传的问题了
5.2 kotlin 变量和常量
varible(变量) 通过 var 关键字来声明,格式为 var 变量名[:类型] = [初始值]
private var mConfig = RabbitConfig() lateinit var application: Application private var isInit = false
- val 声明的变量是只读变量,它的引用不可更改,事实上我们依然可以更改其中引用对象的可变成员
- const 相当于 java里面的 final,表示一旦初始化便立即被主内存看到,不能被二次赋值
当然 kotlin 也有自动拆箱和装箱将Int翻译成Java的int或Integer以提高性能
private var Int = 8
Kotlin 会自动给属性加上 setter 和 getter 方法
class RabbitConfig( var enable: Boolean = true, var enableLog: Boolean = true, @Transient var uiConfig: RabbitUiConfig = RabbitUiConfig(), var storageConfig: RabbitStorageConfig = RabbitStorageConfig(), var monitorConfig: RabbitMonitorConfig = RabbitMonitorConfig(), var reportConfig: RabbitReportConfig = RabbitReportConfig() )
用Show Kotlin Bytecode 翻译一下结果如下:
如果想重写 set() 或 get() 方法 可以这么做
data class RabbitConfig( var enable: Boolean = true, var enableLog: Boolean = true, @Transient var uiConfig: RabbitUiConfig = RabbitUiConfig(), var storageConfig: RabbitStorageConfig = RabbitStorageConfig(), var monitorConfig: RabbitMonitorConfig = RabbitMonitorConfig(), var reportConfig: RabbitReportConfig = RabbitReportConfig() ) { var age: Int = 10 set(value) { println("setter $value") field = value } val createTimeShow: () -> String get() = { this.toString() } }
5.3 kotlin null 判断
以上声明的变量皆为非空变量,即不允许为空值。如果需要声明一个变量可为空,仅需在变量类型后面加上?
val n: String?=null
声明一个变量可为空,仅需在变量类型后面加上?
// 在使用n的时候,由于n可能为null,直接使用编译器会报错 n.length // 正确的使用方式是,在使用前,做判空处理 // 如果变量为空,只需在变量类型后面加上?,这样就不会访问length属性了 n?.length // 如果确定一个可空变量不为空 // 可以加!!告诉编译器它不为空 n!!.length
5.4 kotlin 字符串模板
val i=10 val s="i=$i"//求值结果为:“i=10” val s="adb" val str="$s.length is ${s.length}"//执行结果为“adb.length is 3”
5.5 kotlin 双冒号操作符
双冒号操作符 表示把一个方法(变量)当做一个参数,传递到另一个方法(变量)中进行使用,和Java8类似
/** * 把功能的名字转换为对应存储数据对象 * */ fun nameToInfoClass(name: String): Class<*> { return when (name) { RabbitMonitorProtocol.BLOCK.name -> RabbitBlockFrameInfo::class.java RabbitMonitorProtocol.APP_SPEED.name -> RabbitAppStartSpeedInfo::class.java RabbitMonitorProtocol.FPS.name -> RabbitFPSInfo::class.java RabbitMonitorProtocol.MEMORY.name -> RabbitMemoryInfo::class.java RabbitMonitorProtocol.EXCEPTION.name -> RabbitExceptionInfo::class.java RabbitMonitorProtocol.NET.name -> RabbitHttpLogInfo::class.java RabbitMonitorProtocol.SLOW_METHOD.name -> RabbitSlowMethodInfo::class.java RabbitMonitorProtocol.BLOCK_CALL.name -> RabbitBlockFrameInfo::class.java RabbitMonitorProtocol.GLOBAL_MONITOR.name -> RabbitAppPerformanceInfo::class.java RabbitMonitorProtocol.ANR.name -> RabbitAnrInfo::class.java else -> RabbitFPSInfo::class.java } }
5.6 kotlin 匿名函数
kotlin 正常函数
//---------------------案例一-------------------------- a(fun b(param: Int): String { return param.toString() }); val d = fun b(param: Int): String { return param.toString() } //---------------------案例二-------------------------- view.setOnClickListener(new OnClickListener() { @Override void onClick(View v) { switchToNextPage(); } });
kotlin 匿名函数
//-----------------------案例一------------------------ a(fun(param: Int): String { return param.toString() }); val d = fun(param: Int): String { return param.toString() } //-----------------------案例二------------------------ fun setOnClickListener(onClick: (View) -> Unit) { this.onClick = onClick } view.setOnClickListener(fun(v: View): Unit) { switchToNextPage() })
5.7 kotlin lambda 语法糖
view.setOnClickListener() { v: View -> switchToNextPage() } //----------------------------------------------- view.setOnClickListener { v: View -> switchToNextPage() } //----------------------------------------------- mSimpleListRv.setOnClickListener { startActivity(Intent(this, SimpleListActivity::class.java)) } //----------------------------------------------- view.setOnClickListener { switchToNextPage() it.setVisibility(GONE) }
5.8 kotlin 表达式
5.8.1 kotlin for循环 和 范围 表达式
5.8.1.1 kotlin for循环
// -----------------------正序遍历----------------------- for (index in 1..100){ print(index) }
5.8.1.2 范围 表达式
// -----------------------倒序遍历----------------------- for (index in 100 downTo 1){ print(index) } // -----------------------不使用1作为遍历的步长----------------------- for (index in 1..100 step 2){ print(index)//会输出1..3..5...... } // -----------------------创建一个不包含末尾元素的区间----------------------- for (index in 1 until 10){ println(index)//输出1..9 } // -----------------------遍历一个数组/列表,想同时取出下标和元素----------------------- val array = arrayOf("a", "b", "c") for ((index,e) in array.withIndex()){ println("下标=$index----元素=$e") } // -----------------------遍历一个数组/列表,只取出下标----------------------- val array = arrayOf("a", "b", "c") for (index in array.indices){ println("index=$index")//输出0,1,2 } // -----------------------遍历取元素----------------------- val array = arrayOf("a", "b", "c") for (element in array){ println("element=$element")//输出a,b,c }
5.8.2 kotlin 枚举和 when 表达式
5.8.2.1 kotlin 枚举
Kotlin中,枚举类型以类的形式存在,因此叫做枚举类,详细代码如下:
enum class Color { RED, GREEN, BLUE } //---------------使用------------------- var color: Color = Color.BLUE var color2 = Color.GREEN // 比较两个枚举类型变量 var bool: Boolean = color == color2 //---------------为枚举值指定数值------------------- enum class Direction private constructor(var value: Int) { NORTH(1), WEST(2), EAST(3), SOUTH(4) }
5.8.2.2 kotlin when 表达式
when 表达式 可以支持自动转型(Auto-casting),详细代码如下:
when (view) { is TextView -> toast(view.text) is RecyclerView -> toast("Item count = ${view.adapter.itemCount}") is SearchView -> toast("Current query: ${view.query}") else -> toast("View type not supported") }
5.8.3 kotlin 中缀表达式
kotlin 中缀表达式只有一个参数,且用infix修饰的函数,这就是我们所说的自定义运算符的中缀表达式,详细代码如下:
// 书 class Book{ // 传入任意类型,返回一个Boolean类型的参数 infix fun on(any: Any): Boolean{ return true } } // 桌子 class Desk fun main(args: Array<String>) { if(Book() on Desk()){ println("书在桌上") } }
5.8.3 kotlin 复合表达式
5.8.3.1 '?.'
?.表示,如果foo这时候是一个空的,则返回null,否则就返回foo.bar(),详细代码如下:
if (foo != null){ return foo.bar() }else{ return null }
5.8.3.2 '?:'
?: 作用是当数据非空时,直接返回数据,而当数据为空时,返回合并到的数据。利用该运算符,可以很容易的把可空类型转换为非空类型,详细代码如下:
if(foo!=null) { foo } else { bar } foo?.length?:-1
5.8.3.3 '!!'
Kotlin 中 !! 表示非空断言运算符,详细代码如下:
if(foo!=null) { foo }else { return NullPointerException }
5.8.3.4 'as?'
Kotlin 可以使用安全转换操作符as?,它可以在失败时返回null,详细代码如下:
foo as? type if(foo is Stype) { foo as Type }else { null }
5.8.3.5 '?'
?表示可空类型与非空类型,Kotlin 的类型系统旨在消除来自代码空引用的危险,详细代码如下:
foo? var foo?="abc" foo=null // 编译成功 foo可为空 var foo="abc" foo=null // 编译失败 foo不可以为空
六. Kotlin 面向对象
6.1 kotlin 继承和构造
kotlin中继承全部使用“:”,不区分extend或implement,但是有几个规则需要注意一下:
6.2 kotlin 类
6.2.2 kotlin object 类
object 全局声明的对象只有一个,所以他是天生的单例模型
6.2.2 kotlin data 类
在Kotlin里面声明一个data类需要满足以下条件:
- data类必须要有一个构造方法,且包含至少一个参数
- 该data类构造参数强制使用 val 或 var 进行声明
- data class 之前没有 abstract , open 或 inner 进行修饰
6.2.3 kotlin 内部类
6.3 kotlin 接口
6.4 kotlin 伴生对象
6.5 kotlin 修饰符
6.5.1 限制修饰符
- val 翻译成字节码就是 final
private
- internal
- by
Kotlin 中 by 关键字用来简化实现代理 (委托) 模式,不仅可以类代理,还可以代理类属性, 监听属性变化
6.5.2 可见修饰符
嵌套类的用法: 如果要在 Kotlin 中嵌套一个类,需要在该内部类加 inner修饰
//嵌套类属于静态类和外部类没任何关系 fun main(args : Array<String>){ var ot = OutClass().innerClass() ot.hello() } class OutClass{ var name ="李武" //inner表示内部类 inner class innerClass{ var name = "张三" fun hello(){ println("你好$name") //内部类使用this,访问外部类的变量 println("你好${this@OutClass.name}") } } }
七. 总结
本文先从kotlin概念带大家进入kotlin语言,然后说了一下kotlin和java8的异同以及相互转换方式,最后对Kotlin基础语法进行一一阐述,如: kotlin 方法和变量使用,kotlin字符串模板, lambada表达式,以及各种表达式的实际运用。好了今天的kotlin就说到这里了,如果大家对此有什么疑问欢迎到评论区留言~