主函数
- fun main(args: Array<String>){
- println("Hello World")
- }
- 复制代码
变量
1、常量
val修饰常量,编译器规定常量必须初始化,若不想初始化,可用**by lazy{}**对常量进行懒加载
- val a: Int = 1 // 强类型常量
- val b = 2 // 弱类型常量
- const val c = "Hello" // 编译器常量
- val a: String by lazy{"lazy init"} // 懒加载常量
- 复制代码
2、变量
var修饰变量,编译器规定变量必须初始化,若不想初始化,可用lateinit关键字限制报错
- lateinit var a //未初始化变量
-
- var x = 5 //初始化变量
- var x1 = "x is $x" //获取变量的值:$变量
- var x2 = "${x1.replace("is","was")}" //内嵌表达式:${表达式}
-
- var str = """ //段落
- <html>
- <a href="">go</a>
- </html>
- """
- 复制代码
3、空值检测
- println(value?.size) //if not null
- println(value?.size ?: "empty") //if not null and else
- println(value.firstOrNull() ?: "") //if not null and get first
- println(values["key"] ?: a + b) //if not null and else + 表达式
- value?.let{ } //if not null + 代码块
- value!!.let{ } //告诉编译器不需要判空
- 复制代码
4、字符串比较
==:在kt中相当于java的equals() ===:在kt中相当于java的==
数组
1、定义
- //每种基本类型都有对应的数组创建方法,类似于定制版
- var array:IntArray = intArrayOf(1,3,5,7)
- var array:CharArray = charArrayOf('H','E','L','L','O')
- //基于泛性的创建方法,泛型也可省略,类似于通用版
- var array:Array<Char> = arrayOf('H','E','L','L','O')
- 复制代码
2、数组和字符串转换
- //第一种形式
- var array:Array<Char> = arrayOf('H','E','L','L','O')
- println(array.joinInString(""))
- //第二种形式
- var array:CharArray = charArrayOf('H','E','L','L','O')
- println(String(array))
- 复制代码
3、数组遍历
- var array:Array<Char> = arrayOf('H','E','L','L','O')
- //第一种形式
- array.forEach{println(it)}
- //第二种形式
- array.forEach{::println}
- //第三种形式
- for((index,value) in array.withIndex()){
- println("$index -> $value")
- }
- 复制代码
函数
1、有返回值的函数
- //第一种形式
- fun sum(a: Int, b: Int): Int {return a + b}
- //第二种形式
- fun sum(a: Int, b: Int) = return a + b
- //第三种形式
- fun sum(a: Int, b: Int) = a + b
- 复制代码
2、无返回值的函数
Unit类型相当于Void类型,Unit返回类型可以省略不写
- fun printSum(a: Int, b: Int): Unit { …… }
- 复制代码
3、默认参数的函数
- fun foo(a: Int = 0, b: String = "") { …… }
- 复制代码
4、变长参数的函数
变长参数由vararg关键字决定,数组参数可通过*方式传参,第一个参数可以不使用名字指定,最后个参数必须使用具名参数
- fun say(double: Double,vararg ints: Int,string: String) { …… }
-
- val array = intArrayOf(1,3,4,5)
- say(2.0,*array,string = "Hi")
- 复制代码
5、扩展函数
你可以给父类添加一个方法,这个方法将可以在所有子类中使用
- fun Activity.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
- Toast.makeText(this, message, duration).show()
- }
- 复制代码
6、智能类型推测
判断一个对象是否为一个类的实例,可以使用is关键字与Java中的instanceof关键字类似,但在Kotlin中如果已经确定了一个对象的类型,可以在接下来的代码块中直接作为这个确定类型使用
- fun getStringLength(obj: Any): Int? {
- if (obj is String) {return obj.length} //类型判断后,obj会被系统自动转换为String类型
- if (obj !is String){} //同时还可以使用!is,来取反
- return null //代码块外部的obj仍然是Any类型的引用
- }
- 复制代码
7、复合函数
复合函数指的是函数中存在另一个函数,类似于数学的f(g(x))
- infix fun <P1,P2,R> Function1<P1,P2>.andThen(function: Function1<P2,R>): Function1<P1,R>{
- return fun(p1:P1): R{
- return function.invoke(this.invoke(p1))
- }
- }
-
- var add = {i: Int -> i + 5}
- var plus = {i: Int -> i * 2}
- var addAndPlus = add andThen plus
- println(addAndPlus(8)) // (8+5)*2=26
- 复制代码
8、函数的科理化
函数的科理化指的是函数中传递的多个参数可转换为多个函数来进行链接
- //科理化前的函数
- fun log(tag: String,target: OutputStream,message: Any?){
- target.write("$tag $message\n".toByteArray())
- }
- log("Hensen",System.out,"HelloWorld")
-
- //科理化后的函数
- fun log(tag: String)
- = fun(target: OutputStream)
- = fun(message: Any?)
- = target.write("$tag $message\n".toByteArray())
- log("Hensen")(System.out)("HelloWorld")
- 复制代码
Lambda表达式
1、定义Lambda表达式
- var sum = {arg1: Int,arg2: Int ->
- arg1 + arg2
- }
- //使用第一种方式
- sum(1,2)
- //使用第二种方式
- sum.invoke(1,2)
- 复制代码
2、带有return的Lambda表达式
Lambda表达式并不是函数,如果直接return,会退出当前调用Lambda表达式的函数,而不是退出当前的Lambda表达式,可以使用**@别名**的方式退出
- var array:Array<Char> = arrayOf('H','E','L','L','O')
- array.forEach ForEach@{
- if(it == 'L')return@ForEach
- println(it)
- }
- 复制代码
3、带有run的Lambda表达式
调用某对象的run函数,在函数块内可以通过this指代该对象。返回值为函数块的最后一行或指定return表达式
- val a = "string".run {
- print(this) //string
- 3
- }
- println(a) //3
- 复制代码
4、带有let的Lambda表达式
调用某对象的let函数,则该对象为函数的参数。在函数块内可以通过it指代该对象。返回值为函数块的最后一行或指定return表达式
- val a = "string".let {
- println(it) //string
- 3
- }
- println(a) //3
- 复制代码
5、带有with的Lambda表达式
它是将某对象作为函数的参数,在函数块内可以通过this指代该对象。返回值为函数块的最后一行或指定return表达式
- val a = with("string") {
- println(this) //string
- 3
- }
- println(a) //3
- 复制代码
6、带有apply的Lambda表达式
调用某对象的apply函数,在函数块内可以通过this指代该对象。返回值为该对象自己
- val a = "string".apply {
- println(this) //string
- }
- println(a) //string
- 复制代码
7、带有also的Lambda表达式
调用某对象的also函数,则该对象为函数的参数。在函数块内可以通过it指代该对象。返回值为该对象自己
- val a = "string".also {
- println(it) //string
- }
- println(a) //string
- 复制代码
8、小结
- run:使用this指定当前对象,最后一行为返回值
- let:使用it指定当前对象,最后一行为返回值
- with:使用this指定当前对象,最后一行为返回值,写法上有区别
- apply:使用this指定当前对象,返回值为该对象自己
- also:使用it指定当前对象,返回值为该对象自己
表达式
1、When表达式
- fun transform(x: Int){
- return when (x) {
- is Int -> println("$x is Int")
- in 1..100 -> println("$x is in 1-100")
- !in 1..100 -> println("$x is not in 1-100")
- //else不写则不做默认操作
- else -> throw IllegalArgumentException("Invalid x param value")
- }
- }
- 复制代码
或者
- fun describe(obj: Any): String =
- when (obj) {
- 1 -> "One"
- "Hello" -> "Greeting"
- is Long -> "Long"
- !is String -> "Not a string"
- else -> "Unknown"
- }
- 复制代码
2、try-catch表达式
- fun test() {
- val result = try {
- count()
- } catch (e: ArithmeticException) {
- throw IllegalStateException(e)
- }
- }
- 复制代码
3、if表达式
- fun foo(param: Int) {
- val result = if (param == 1) {
- "one"
- } else if (param == 2) {
- "two"
- } else {
- "three"
- }
- }
- 复制代码
4、with表达式
- class Turtle {
- fun penDown()
- fun penUp()
- fun turn(degrees: Double)
- fun forward(pixels: Double)
- }
-
- val myTurtle = Turtle()
- with(myTurtle) { // 画一个 100 像素的正方形
- penDown()
- for(i in 1..4) {
- forward(100.0)
- turn(90.0)
- }
- penUp()
- }
- 复制代码
5、for表达式
- val items = listOf("apple", "banana", "kiwifruit")
- for (item in items) {
- println(item)
- }
-
- val items = listOf("apple", "banana", "kiwifruit")
- for (index in items.indices) {
- println("item at $index is ${items[index]}")
- }
- 复制代码
6、while表达式
- val items = listOf("apple", "banana", "kiwifruit")
- var index = 0
- while (index < items.size) {
- println("item at $index is ${items[index]}")
- index++
- }
- 复制代码
7、中缀表达式
使用infix关键字创建中缀表达式
- Class Book{
- infix fun on(any: Any): Boolean{
- return false
- }
- }
-
- Class Desk{
-
- }
-
- if(Book on Desk){
- println("book on the desk")
- }
- 复制代码
闭包
1、函数内部可以定义函数,属于闭包
- fun add(x: Int): (Int)-> Int{
- return fun(y: Int): Int{
- return x + y
- }
- }
- 复制代码
2、闭包持有函数内部的运行状态
- fun justCount():() -> Unit{
- var count = 0 //被函数内部持有
- return {
- println(count++)
- }
- }
-
- fun main(args: Array<String>) {
- val count = justCount()
- count() // 输出结果:0
- count() // 输出结果:1
- count() // 输出结果:2
- }
- 复制代码
3、自行闭包
自执行闭包就是在定义闭包的同时直接执行闭包,一般用于初始化上下文环境
- { x: Int, y: Int ->
- println("${x + y}")
- }(1, 3)
- 复制代码
运算符
1、自定义运算符
- class Complex(var arg1: Double,var arg2: Double){
- operator fun plus(other: Complex): Complex{
- return Complex(arg1 + other.arg1,arg2 + other.arg2)
- }
-
- operator fun plus(other: Int): Complex{
- return Complex(arg1 + other,arg2)
- }
-
- oprator fun invoke(): Double{
- return Math.hypot(arg1,arg2)
- }
-
- overide fun toString(): String{
- return "${arg1} and ${arg2}"
- }
- }
-
- val c1 = Complex(3.0,4.0)
- val c1 = Complex(2.0,5.0)
- println(c1 + c2) //5.0 and 9.0
- println(c1 + 5) //8.0 and 4.0
- println(c1()) //5
- 复制代码
区间语句
1、定义区间
- var range = 0..1024 //[0,1024]闭区间
- var range = 0 until 1024 //[0,1024)半开区间
- var range = 0..-1 //空区间
- 复制代码
2、检查x是否在指定区间里面
- val x = 10
- val y = 9
- if (x in 1..y+1) {
- println("fits in range")
- }
- 复制代码
3、检查list.size是否在list的索引上
- val list = listOf("a", "b", "c")
-
- if (-1 !in 0..list.lastIndex) {
- println("-1 is out of range")
- }
- if (list.size !in list.indices) {
- println("list size is out of valid list indices range too")
- }
- 复制代码
4、区间遍历
- for (x in 1..10 step 2) {
- print(x) //13579
- }
- for (x in 9 downTo 0 step 3) {
- print(x) //9630
- }
- 复制代码
集合
1、初始化
- val mutableList = mutableListOf(0, 1) //可读写List对象
- var list = listOf(0, 1, 2) //可读List对象
- val set = setOf(1, 2, 4) //可读Set对象
- 复制代码
2、集合遍历
- val items = listOf("a", "b", "c")
- for (item in items) {
- println(item)
- }
- 复制代码
3、集合判断
- val items = listOf("apple", "balanace", "coffee")
- when {
- "orange" in items -> println("juicy")
- "apple" in items -> println("apple is fine too")
- }
- 复制代码
映射
1、初始化
- val map = mutableMapOf("a" to 1, "b" to 2, "c" to 3) //可读写Map对象
- val map = mapOf("a" to 1, "b" to 2, "c" to 3) //可读Map对象
- 复制代码
2、访问Map
- map["key"] = value
- 复制代码
3、遍历Map
- for ((k, v) in map) {
- println("$k -> $v")
- }
- 复制代码
构造方法
1、主构造函数
Kotlin的构造函数可以写在类头中,跟在类名后面,如果有注解还需要加上关键字constructor
- class Person(private val name: String) {
-
- fun sayHello() {
- println("hello $name")
- }
- }
- 复制代码
在主构造函数中不能有任何代码实现,如果有额外的代码需要在构造方法中执行,你需要放到init代码块中执行
- class Person(private var name: String) {
-
- init {
- name = "Zhang Tao"
- }
-
- fun sayHello() {
- println("hello $name")
- }
- }
- 复制代码
2、次构造函数
存在两个或两个以上的构造方法时,可以增加次构造方法
- class Person(private var name: String) {
-
- private var description: String? = null
-
- init {
- name = "Zhang Tao"
- }
-
- constructor(name: String, description: String) : this(name) {
- this.description = description
- }
-
- fun sayHello() {
- println("hello $name")
- }
- }
- 复制代码
类与对象
1、输出类名
- println(HelloWorld::class.java.simpleName) //输出类名
- println(HelloWorld::class.java.name) //输出包名+类名
- 复制代码
2、创建对象
- val rectangle = Rectangle(5.0, 2.0)
- val triangle = Triangle(3.0, 4.0, 5.0)
- 复制代码
3、数据类
data修饰的类称之为数据类,当data修饰后,会自动将所有成员用operator声明,即为这些成员生成getter()和setter()
- data class Customer(val name: String, val email: String)
- 复制代码
编译器自动从主构造函数中的属性导入下面这些成员函数
- equals()
- hashCode()
- toString()
- componentN():函数返回对应着声明的参数顺序
- copy()
- 复制代码
4、内部类
Kt默认的内部类为静态内部类,可以使用inner关键字将内部类变为非静态内部类,且可使用注解去获取外部类的成员属性
- class Outter{
- var a = 5
- inner class Inner{
- var a = 6
- fun getOutterA(){
- println(this@Outter.a)
- }
- }
- }
- 复制代码
5、单例类
object关键字表示该类是单例
- class Single private constructor() {
- companion object {
- fun get():Single{
- return Holder.instance
- }
- }
-
- private object Holder {
- val instance = Single()
- }
- }
- 复制代码
或者
- object Resource {
- val name = "Name"
- }
- //使用
- Resource.INSTANCE.name
- 复制代码
6、枚举类
枚举默认没有数值,如果需要固定类型的数值,可在类名后声明参数类型
- enum class Programer(val id: Int) {
- JAVA(0), KOTLIN(1), C(2), CPP(3), ANDROID(4);
- fun getTag(): String{
- return "$id + $name"
- }
- }
- //使用
- println(Programer.JAVA.getTag())
- 复制代码
7、密封类
sealed修饰的类称为密封类,用来表示受限的类层次结构
- sealed class BaseClass {
- class Test1 : BaseClass() {
- override fun test() {
- println("Test1实例")
- }
-
- }
- class Test2 : BaseClass() {
- override fun test() {
- println("Test2实例")
- }
- }
- object Test3 : BaseClass() {
- override fun test() {
- println("Test3实例")
- }
- }
- open fun test() {
- println("BaseClass实例")
- }
- }
- 复制代码
密封类与枚举的区别:
密封类是枚举类的扩展 枚举类型的值集合是受限的,且每个枚举常量只存在一个实例 密封类的一个子类可以有可包含状态的多个实例 8、继承
在class中加open关键字即可被继承
- open class Person(var name:String, var age:Int){
-
- }
- 复制代码
9、接口代理
接口代理表示代理人可直接调用接口代理的方法
- //代理driver和writer,当执行manager.driver(),Manager类会去调用代理的driver.driver()
- class Manager(val driver: Driver,val writer: Writer):Driver by driver,Writer by writer
-
- interface Driver{fun driver()}
- interface Wirter{fun wirter()}
- 复制代码
10、伴生对象
用companion关键字修饰对象内的方法,我们称companion修饰的对象为伴生对象,本质是静态方法。如果在Java文件中想通过类名的方式去调用静态方法,则需要加入注解才可以使用
- class StringUtils {
- companion object {
- @JvmStatic
- fun isEmpty(str: String): Boolean {
- return "" == str
- }
- @JvmField
- var TAG = "StringUtils"
- }
- }
- 复制代码
11、方法重载
由于Kt中有默认参数的性质,所以方法的重载可以用默认参数来实现,如果在Java文件中想使用Kt重载的话,就需要加入注解才可以使用
- class StringUtils {
- @JvmOverloads
- fun a(int: Int = 0): Int{
- return int
- }
- }
- 复制代码
12、匿名对象
使用object对象表示匿名对象
- btn?.setOnClickListener(object : View.OnClickListener{
- override fun onClick(v: View?) {
-
- }
- })
- 复制代码
常用操作符
Kotlin的操作符跟RxJava基本一致
1、下标操作类
- contains:判断是否有指定元素
- elementAt:返回对应的元素,越界会抛IndexOutOfBoundsException
- firstOrNull:返回符合条件的第一个元素,没有返回null
- lastOrNull:返回符合条件的最后一个元素,没有返回null
- indexOf:返回指定元素的下标,没有 返回-1
- singleOrNull:返回符合条件的单个元素,如有没有符合或超过一个,返回null
2、判断类
- any:判断集合中 是否有满足条件的元素
- all:判断集合中的元素是否都满足条件
- none:判断集合中是否都不满足条件,是则返回true
- count:查询集合中满足条件的元素个数
- reduce:从第一项到最后一项进行累计
3、过滤类
- filter:过滤 掉所有满足条件的元素
- filterNot:过滤所有不满足条件的元素
- filterNotNull:过滤NULL
- take:返回前n个元素
4、转换类
- map:转换成另一个集合
- mapIndexed:除了转换成另一个集合,还可以拿到Index
- mapNotNull:执行转换前过滤掉 为 NULL 的元素
- flatMap:自定义逻辑合并两个集合
- groupBy:按照某个条件分组,返回Map
5、排序类
- reversed:反序
- sorted:升序
- sortedBy:自定义排序
- sortedDescending:降序
6、实战操作符
- val fruits = listOf("banana", "avocado", "apple", "kiwifruit")
- fruits
- .filter { it.startsWith("a") }
- .sortedBy { it }
- .map { it.toUpperCase() }
- .forEach { println(it) }
- 复制代码
特性
1、懒加载
- val p: String by lazy {
- // 计算该字符串
- }
- 复制代码
2、安全类型转换
父类转成子类会抛出类型转换失败的错误,如果采用**as?**的方式,则返回null
- var child: Child = parent as? Child
- 复制代码
3、输出可执行文件
在Gradle添加依赖指定main函数文件,后缀名为Kt
- apply plugin:'application'
- mainClassName = "com.hensen.android.MyCalcKt"
- 复制代码
刷新Gradle,在Gradle右边栏点击distribution/installDist,生成的程序在build/install目录下
4、internal关键字
在变量中使用internal关键字表示成员变量只允许在模块内能被访问到
- internal var name
- 复制代码
5、尾递归
对于递归函数,如果递归函数并未对递归的结果进行操作,则可以使用tailrec关键字将递归声明为尾递归,尾递归会优化代码,将递归转换成迭代
- data class ListNode(val value: Int,var next: ListNode?)
- //对递归的结果并未操作,属于尾递归
- tailrec fun findListNode(head: ListNode?,value: Int): ListNode?{
- head?: return null
- if(head.value == value) return head
- return findListNode(head.next,value)
- }
- //对递归的结果进行乘法运算,不属于尾递归
- fun factorial(n: Long): Long{
- return n * factorial(n - 1)
- }
- 复制代码
Android相关
1、view.find
使用Ktolin的拓展函数,view.find替代findViewById
- var textView = view.find(R.id.textView)
- 复制代码
2、observable
Delegates.observable可以监听当前的变量值的变化,改变变量的值,即可触发observable
- private var mCurrentState: Int by Delegates.observable(-1) { _, old, new ->
- if (old != new) {
- RxBus.getDefault().post(ChannelPK_OnModelChange_Rank_EventArgs(new == 1))
- MLog.info(PKModelManager.TAG, "rank mode : $old -> $new")
- }
- }
-
- fun onModelChange() {
- mCurrentState = 1 //改变变量的值,即可触发observable
- }
- 复制代码
3、bundle
创建bundle已经不需要再去执行其各种put方法
- val bundle = bundleOf(
- "KET_INT" to 1,
- "KET_LONG" to 2L,
- "KET_BOOLEAN" to true,
- "KEY_NULL" to null,
- "KEY_ARRAY" to arrayOf(1, 2)
- )
- 复制代码
4、Parcelize
Parcelize已经不需要再写什么代码了,只需要继承和注解
- @Parcelize
- data class User(val name: String,val age: Int): Parcelize
- 复制代码
- @Parcelize的使用需要在gradle声明变量
-
- androidExtensions {
- experimental = true
- }
- 复制代码
5、Serializable
指定Serializable的名字
- class Book(@SerializedName(TXT) var txt: String)
- 复制代码
6、postDelay
postDelay支持闭包和lambda表达式
- handler.postDelayed(50) {
- // lambda
- }
- 复制代码
7、注解
如果说在Java文件中需要使用到KT的变量、静态方法、重载方法等,就需要注解声明
- @JvmField:将属性编译为Java变量
- @JvmStatic:将伴生对象编译为Java静态方法
- @JvmOverloads:默认参数生成重载方法
- @file:JvmName:指定Kotlin文件编译后的类名