主函数
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文件编译后的类名
网友评论