在2019年的Google 1/0大会上Kotlin被选为Android开发首选语言
Kotlin文件会被Kotlin 编译器编译成Java字节码文件,字节码文件会被jar工具打包成jar包,最终会被各平台的打包工具输出成我们的应用程序
Byte、Short、Int、Long、Float、Double
数组的创建
- // arrayOf
- val array: Array<Int> = arrayOf(1, 2, 3)
-
- // arrayOfNulls
- val array1: Array<Int?> = arrayOfNulls<Int>(3)
- array1[0] = 4
- array1[1] = 5
- array1[2] = 6
-
- // Array(5)的构造函数
- val array2: Array
= Array(5) { i -> - (i * i).toString()
- }
-
- // intArrayOf(), doubleArrayOf()
- val x: IntArray = intArrayOf(1, 2, 3)
- println("x[0] + x[1] = ${x[0] + x[1]}")
-
- // 大小为5,值为【0,0,0,0,0】的整型数组
- val array3 = IntArray(5)
-
- // 大小为5,值为【1,1,1,1,1】的整型数组
- val array4 = IntArray(5) { 1 }
-
- // 大小为5、值为【0,1,2,3,4】的整形数组(值初始化为其索引值)
- val array5 = IntArray(5) { it * 1 }
- println(array5[4])
数组的遍历
- // 数组遍历
- for (item in array) {
- println(item)
- }
-
- // 带索引遍历数组
- for (i in array.indices) {
- println("$i -> ${array[i]}")
- }
-
- // 遍历元素(带索引)
- for ((index, item) in array.withIndex()) {
- println("$index -> $item")
- }
-
- // forEach遍历数组
- array.forEach {
- println(it)
- }
-
- // forEach增强版
- array.forEachIndexed { index, item ->
- println("$index -> $item")
- }
集合的可变形与不可变性--以mutable为前缀的为可变集合
- //不可变集合
- val stringList: List
= listOf("one", "two", "one") -
- //可变集合
- val numbers: MutableList<Int> = mutableListOf(1, 2, 3, 4)
集合排序:
- val number3 = mutableListOf(1, 2, 3, 4)
-
- // 随机排序
- number3.shuffle()
-
- // 从小到大
- number3.sort()
-
- // 从大到小
- number3.sortDescending()
-
- // 使用sortBy进行排序,适合单条件排序
- lauguageList.sortBy { it.score }
-
- // 使用sortWith进行排序,适合多条件排序
- lauguageList.sortWith(compareBy({
- it.score
- }, { it.name }))
方法声明
- //方法申明
- fun learn(days: Int): Boolean {
- return days > 100
- }
- fun 方法(参数):返回值{
- 方法体
- }
方法可以直接定义在文件中
- package com.lf.testkotlin
-
- fun functionLearn(days: Int): Boolean {
- return days > 100
- }
成员方法:类().成员方法
- fun main() {
- Person().test1()
- }
-
- class Person {
-
- fun test1() {
- println("成员方法")
- }
- }
静态方法(类方法):使用伴生对象来实现类方法 类.类方法
- fun main() {
- Person.test2()
- }
-
- class Person {
- companion object {
- fun test2() {
- println("companion object 实现类方法")
- }
- }
- }
工具类:Object关键字来修饰,内部所有的方法都是静态的
- package com.lf.testkotlin
-
- object NumUtil {
- fun double(num: Int): Int {
- return num * 2
- }
- }
-
- fun main() {
- NumUtil.double(2)
- }
单表达式方法:当方法返回单个表达式时,可以省略花括号并且在 = 之后指定代码体即可
fun double(x: Int): Int = x * 2
参数默认值:方法参数可以有默认值,当省略相应的参数时使用默认值,与其java相比,减少重载数量
- fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) {
-
- }
可变数量的参数:vararg
- fun append(vararg str: Char): String {
- val result = StringBuffer()
- for (char in str) {
- result.append(char)
- }
- return result.toString()
- }
局部方法:在方法的内部创建方法
- fun magic(): Int {
- fun foo(v: Int): Int {
- return v * v
- }
-
- val v1 = (0..100).random()
- return foo(v1)
- }
无参数的情况
- val/var 变量名 = { 操作的代码 }
-
- eg:
- //源代码
- fun test() {
- println("无参数")
- }
-
- //lambda代码
- val test1 = { println("无参数") }
有参数的情况
- val/var 变量名 : (参数的类型, 参数类型, ...) -> 返回值类型
- = {参数1, 参数2, ... -> 操作参数的代码}
- // 等价于,即表达式的返回值类型会根据操作的代码自推导出来。
- val/var 变量名 = {参数1: 类型, 参数2: 类型, ... ->
- 操作参数的代码}
-
- eg:
- // 源代码
- fun test2(a: Int, b: Int): Int {
- return a + b
- }
-
- // lambda代码
- val test3: (Int, Int) -> Int = { a, b -> a + b }
- //或者
- val test4 = { a: Int, b: Int -> a + b }
it是在当一个高阶方法中Lambda表达式的参数只有一个的时候可以使用it来使用此参数
- // 这里举例一个语言自带的一个高阶方法filter,此方法的作用是过滤掉不满足条件的值
- val arr = arrayOf(1, 3, 5, 7, 9)
- // 过滤掉数组中元素小于5的元素,取其第一个打印。这里的it就表示每一个元素。
- println(arr.filter { it < 5 }.component1())
-
- testClosure(1)(2) {
- println(it)
- }
在使用Lambda表达式的时候,可以用下划线(_)表示未使用的参数,表示不处理这个参数
- val map = mapOf("key1" to "value1", "key2" to "value2", "key3" to "value3")
- map.forEach { (key, value) ->
- println("$key \t $value")
- }
-
- // 不需要key的时候
- map.forEach { (_, value) -> println(value) }
函数作为参数
- /**
- * eg: 实现一个能够对集合元素进行求和的高阶函数,并且每遍历一个集合元素要有回调
- */
- fun List
.sum(callback: (Int) -> Unit): Int { - var result = 0
- for (v in this) {
- result += v
- callback(v)
- }
- return result
- }
- // 调用
- val list = listOf(1, 2, 3)
- val result = list.sum { println("it:${it}") }
- println("${result}")
函数作为返回值
- /**
- * eg: 实现一个能够对集合元素进行求和的高阶函数,并且返回一个声明为(scale: Int)-> Float的函数
- */
- fun List
.toIntSum(): (scale: Int) -> Float { - println("第一层函数")
- return fun(scale): Float {
- var result = 0f
- for (v in this) {
- result += v.toInt() * scale
- }
- return result
- }
- }
- // 调用
- val listString = listOf("1", "2", "3", "4")
- val result2 = listString.toIntSum()(2)
- println("计算结果:${result2}")
特性:
好处:
举例:
实现一个接受一个testClosure方法,该方法要接受一个Int类型的v1参数,同时能够返回一个声明为(v2: Int, (Int) -> Unit)的函数,并且这个函数能够计算v1与v2的和。
- fun testClosure(v1: Int): (v2: Int, (Int) -> Unit) -> Unit {
- return fun(v2: Int, printer: (Int) -> Unit) {
- printer(v1 + v2)
- }
- }
- // 调用
- testClosure(1)(2) {
- println(it)
- }
把里面的字段给解构出来
- data class Result(val message: String, val code: Int)
-
- fun test11() {
- var result = Result("message", 0)
- // 解构
- val (message, code) = result
- println("message:${message} code:${code}")
- }
val fun1 = fun(x: Int, y: Int): Int = x + y
- fun literal() {
- // 定义了一个变量tmp,而该变量的类型就是(Int)-> Boolean
- var temp: ((Int) -> Boolean)? = null
- // { num -> (num > 10) } 就是方法字面值
- temp = { num -> (num > 10) }
- println("temp(11):${temp(11)}")
- }
- /**
- * 主构造方法(主构造方法constructer()可以省略)
- */
- class KotlinClass constructor(name: String) {
- // 次构造方法
- constructor(view: View, name: String) : this(name) {
- println("name:$name")
- }
-
- constructor(view: View, name: String, index: Int) : this(name) {
- println("name:$name,index:$index")
- }
- }
父类必须用open修饰,需要被覆盖的方法也需要open修饰,需要被覆盖的属性也需要open修饰
- open class Animal(age: Int) {
- init {
- println(age)
- }
-
- open val foot: Int = 0
- open fun eat() {
-
- }
- }
-
- class Dog : Animal {
- constructor(age: Int) : super(age)
-
- override val foot = 4
- override fun eat() {
- super.eat()
- }
- }
- //其初始器(initializer)、getter和setter都是可选的。如果属性类型可以从初始器(或者从其getter返回值)中推断出来,也可以省略
- var
[: ] [ = ] - [
] - [
] -
- eg:
-
- val simple: Int? // 类型Int、默认getter、必须在构造方法中初始化
-
- //定义了一个自定义的getter,每次访问该属性时都会调用它。
- val isClose: Boolean
- get() = Calendar.getInstance().get(Calendar.HOUR_OF_DAY) > 11
-
- //定义了一个自定义的setter,每次给属性赋值时都会调用它
- var score: Float = 0.0f
- get() = if (field < 0.2f) 0.2f else field * 1.5f
- set(value) {
- println(value)
- }
-
- 属性延迟初始化
-
- lateinit var shop: Shop2
- fun setup() {
- shop = Shop2()
- }
-
- fun test() {
- // ::表示创建成员引用或类引用
- if (::shop.isInitiaized) println(shop.address)
- }
- /**
- * 抽象方法
- */
- abstract class Printer {
- abstract fun print()
- }
-
- class FilePrinter : Printer() {
- override fun print() {
-
- }
- }
-
- /**
- * 接口
- */
- interface Study {
- val time: Int//抽象的
- fun discuss()
- fun learnCourses() {
- println("Android 架构师")
- }
- }
-
- class StudyAS(override val time: Int) : Study {
- override fun discuss() {
-
- }
- }
必须要有至少一个参数,并且不能被定义成open或者抽象的,不能被继承。
- /**
- * 数据类,可以有自己的类体,包括属性和方法
- */
- data class Address(val name: String, val number: Int) {
- var city: String = ""
- fun print() {
- println(city)
- }
- }
- open class Address2(name: String) {
- open fun print() {
-
- }
- }
-
- class Shop2 {
- var address: Address2? = null
- fun addAddress(address2: Address2) {
- this.address = address2
- }
- }
-
- fun test3() {
- // 如果超类型有一个构造方法,则必须传递适当的构造方法参数给它
- Shop2().addAddress(object : Address2("Android") {
- override fun print() {
- super.print()
- }
- })
- }
-
- fun foo() {
- val adHoc = object {
- var x: Int = 0
- var y: Int = 0
- }
- println(adHoc.x + adHoc.y)
- }
-
- /**
- * 对象的声明
- */
- object DataUtil {
- fun
isEmpty(list: ArrayList<T>): Boolean { - return list?.isEmpty()
- }
- }
- class Student(val name: String) {
- companion object {
- val student = Student("Android")
- fun study() {
- println("Android 架构师")
- }
- }
- }
-
- fun testStudent() {
- println(Student.student)
- Student.study()
- }
泛型接口
- interface Drinks<T> {
- fun taste(): T
- fun price(t: T)
- }
-
- class Sweet {
- val price = 5
- }
-
- class Coke : Drinks<Sweet> {
- override fun taste(): Sweet {
- println("Sweet")
- return Sweet()
- }
-
- override fun price(t: Sweet) {
- println("Coke price:${t.price}")
- }
- }
泛型方法
- /**
- * 泛型方法
- */
- fun
fromJson(json: String, tClass: Class<T>): T? { - // 获取t的实例
- val t: T? = tClass.newInstance()
- return t
- }
泛型约束
在kotlin中out代表协变,in代表逆变,为了加深理解我们可以将kotlin的协变看成java的上界通配符,将逆变看成java的下界通配符
- //和一般的声明很类似,只是在class前面加上了annotation修饰符
- annotation class ApiDoc(val value: String)
-
- @ApiDoc("修饰类")
- class Box {
- @ApiDoc("修饰字段")
- val size = 8
-
- @ApiDoc("修饰方法")
- fun test() {
-
- }
- }
给注解类加注解
- @Target:定义注解能够应用于哪些目标对象;
- @Retention:注解的保留期;
- @Repeatable:标记的注解可以多次应用于相同的声明或类型;
- @MustBeDocumented:修饰的注解将被文档工具提取到API文档中;
@Target
接受一个vararg可变数量的参数,可以同时指定多个作用的目标对象,参数类型限定为AnnotationTarget
- public enum class AnnotationTarget {
- CLASS,// 表示作用对象有类、接口、object对象表达式、注解类
- ANNOTATION_CLASS,//表示作用对象只有注解类
- TYPE_PARAMETER,//表示作用对象是泛型类型参数(暂时还不支持)
- PROPERTY,//表示作用对象是属性
- FIELD,//表示作用对象是字段,包括属性的幕后字段
- LOCAL_VARIABLE,//表示作用对象是局部变量
- VALUE_PARAMETER,//表示作用对象是函数或构造函数的参数
- CONSTRUCTOR,//表示作用对象是构造函数,主构造函数或次构造函数
- FUNCTION,//表示作用对象是函数,不包括构造函数
- PROPERTY_GETTER,//表示作用对象是属性的getter函数
- PROPERTY_SETTER,//表示作用对象是属性的setter函数
- TYPE,//表示作用对象是一个类型,比如类、接口、枚举
- EXPRESSION, //表示作用对象是一个表达式
- FILE,//表示作用对象是一个File
- @SinceKotlin("1.1")
- TYPEALIAS//表示作用对象是一个类型别名
- }
@Retention
接收一个AnnotationRetention类型的参数,该参数有个默认值,默认是保留在运行时期
- @Retention元注解取值主要来源于AnnotationRetention枚举类
- public enum class AnnotationRetention {
- SOURCE,//源代码时期(SOURCE):注解不会存储在输出class字节码中
- BINARY,//编译时期(BINARY):注解会存储在class字节码中,但是对反射不可见
- RUNTIME//运行时期(RUNTIME):注解会存储在class字节码中,也会对反射可见
- }
-
- //交换列表中的两个元素的位置
- fun MutableList
.swap(index1: Int, index2: Int) { - val temp = this[index1]
- this[index1] = this[index2]
- this[index2] = temp
- }
-
- //泛型扩展方法
- fun
MutableList .swap2(index1: Int, index2: Int) { - val temp = this[index1]
- this[index1] = this[index2]
- this[index2] = temp
- }
- //获取字符串中的最后一个元素
- fun String.lastChar():Char = this.get(this.length - 1)
- class Jump {
- companion object {}
- }
-
- fun Jump.Companion.print(str: String) {
- println(str)
- }
let
- //原型
- fun
T.let(f: (T) -> R): R = f(this) -
- //举例
- fun testLet(str: String?) {
- // 避免为null的操作
- str?.let {
- println(it.length)
- }
- //限制作用域
- str.let {
- val str2 = "let作用域"
- println(it + str2)
- }
- }
run
只接收一个lambda函数为参数,以闭包形式返回,返回值为最后一行的值或者指定的return的表达式,在run函数中可以直接访问实例的公有属性和方法。
- //原型
- fun
T.run(f: T.() -> R): R = f() -
- //举例
- data class Room(val address: String, val price: String, val size: Float)
-
- fun testRun(room: Room) {
- room.run {
- println("Room:$address,$price,$size")
- }
- }
apply
调用某对象的apply函数,在函数范围内,可以任意调用该对象的任意方法,并返回该对象。
- //原型
- fun
T.apply(f: T.() -> Unit): T { f(); return this } -
- //举例
- fun testApply() {
- ArrayList
().apply { - add("1")
- add("2")
- add("3")
- }.let {
- println(it)
- }
- }
从结构上来看apply函数和run函数很像,唯一不同点就是它们各自返回的值不一样,run函数是以闭包形式返回最后一行代码的值,而apply函数的返回的是传入对象的本身。
使用Kotlin扩展为控件绑定监听器减少模版代码
- //为Activity添加find扩展方法,用于通过资源id获取控件
- fun
Activity.find(@IdRes id: Int): T { - return findViewById(id)
- }
-
- //为Int添加onClick扩展方法,用于为资源id对应的控件添加onclick监听
- fun Int.onClick(activity: Activity, click: () -> Unit) {
- activity.find
(this).apply { - setOnClickListener {
- click
- }
- }
- }
-
- //使用
- val textView = find
(R.id.text) - R.id.text.onClick(this) {
- textView.text = "kotlin扩展"
- }
- //使用方法
- //1.gradle中引入插件:
- apply plugin: 'kotlin-android-extensions'
-
- //2.在代码中导入:
- import kotlinx.android.synthetic.main.<布局>.*
-
- //3.若需要调用View的合成属性,同时还应该导入
- import kotlinx.android.synthetic.main.view.*
-
- //4.最后可以通过控件id来访问这些控件了
-
- //java
- public class CustomView extends FrameLayout {
- public CustomView(@NonNull Context context) {
- super(context);
- }
-
- public CustomView(@NonNull Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- }
-
- public CustomView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
- }
-
- //kotlin
- class CustomKotlinView @JvmOverloads constructor(
- context: Context,
- attrs: AttributeSet? = null,
- defStyleAttr: Int = 0
- ) : FrameLayout(context, attrs, defStyleAttr) {
-
- }