本篇笔记主要记录过去几年 工作所需Kotlin的简单基础,用来查漏补缺
- 更多参考:https://www.yiibai.com/kotlin
0,Kotlin构建流程和设计理念
Kotlin是一种在java虚拟机上运行的静态类型编程语言 可以和java代码相互运作 在android项目中替代java或与java共存
简洁易用,安全,工具友好,可以使用java的API,代码量少
Kotlin构建流程
kt文件会被kotlin编译器编译成java的字节码文件.class, 字节码文件会被jar工具打包成jar包,然后被各个平台输出应用,比如安卓输出安卓app,iOS输出iOSapp
为啥需要一个kotlin的runtime运行时? 因为kotlin有自己的类库,所以最后运行的时候需要kotlin运行时来关联kotlin的类库辅助运行
1,Kotlin基本类型
数字类型
- Byte 8位 (-128 – 127)
- Short 16位 (-32768 – 32767)
- Int 32位 (-2,147,483,648 – 2,147,483,647)
- Long 64位 (-9,223,372,036,854,775,808 – +9,223,372,036,854,775,807)
- Float 32位 (1.40129846432481707e-45 – 3.40282346638528860e+38)
- Double 64位 (4.94065645841246544e-324 – 1.79769313486231570e+308)
Char 字符数据类型
- Char 4位 (-128 – 127)
Boolean 数据类型
- Boolean 1位 true 或 false
数组
关于创建数组
fun arrayTest(){
//使用arrayOf()创建数组 系统可以推断出类型
var result = arrayOf("Java","Python","C++")
//创建一个元素为null的数组 需要使用泛型类指定数组类型
var result2 = arrayOfNulls<Int>(3)
//创建长度为0的空数组 需要使用泛型类指定数组类型
var result3 = emptyArray<String>()
//创建指定长度,使用Lambda表达式初始化数组元素的数组 可以动态的计算数组元素的值
var arr4 = Array (5,{(it * 2 + 1)})
for(item in arr4){
print(item)// 1 3 5 7 9
}
//如果将基本类型传入Array<T>中,Kotlin会将这些基本类型自动装箱,所以提供了了 ByteArray ShortArray等等
//静态初始化
var doubleArr = doubleArrayOf(1.0,2.0,6.43,3.5,4.65)
//动态操作
var intArr2 = IntArray(5, {it * it})
}
数组常用方法
var result = arrayOf(1,2,3,4)
//使用 Lambda 表达式要求所有数组元素都满足该表达式,如果都满足,那么该方法返回 true
print(result.all({it>2})) //false
//使用 Lambda 表达式要求其中只要有一个数组元素该表达式,如果满足,那么该方法返回 true
print(result.any({it>3})) //true
//将数组转为集合
print(result.asList()) //[1, 2, 3, 4]
//根据数组元素来计算<K,V>对,返回所有<K,V>对组成的 Map集合
print(result.associate({it + 10 to it* it}))//{11=1, 12=4, 13=9, 14=16}
var map= mutableMapOf(5 to 100 , 2 to 120 , -1 to 130)
print(map)//{1=100, 2=120, -1=130}
//将数组转为map对象,并且添加到其它的map中
print(result.associateByTo(map, {it* it})) //{1=1, 2=120, -1=130, 4=2, 9=3, 16=4}
//计算数组所有元素的总和
println(result.fold(0, {ace , e ->ace+ e})) //10
//两个数组,如果长度和顺序都相等,返回true
print(result.contentEquals(result))//true
//复制数组
var result2 = result.copyOf(6)
print(result2.asList())//[1, 2, 3, 4, null, null]
//将数组转为字符串
print(result2.contentToString())//[1, 2, 3, 4, null, null]
//将result2数组从第5(indexWie4)个到第7(index为6)个元素赋值为1
result2.fill(1,4,6)//1是赋给的值 4和6是下标(包含4,不包含6)
print(result2.contentToString())
//对数组进行排序
result.sort()
遍历数组
var arr = Array (5,{(it * 2 + 1)})
for(item in arr){
print(item)// 1 3 5 7 9
}
//带索引遍历数组
for(i in arr.indices){
println("$i -> ${arr[i]}")
}
//遍历元素带索引
for((index,item) in arr.withIndex()){
println("$index-> $item ")
}
arr.forEach{
println(it)
}
arr.forEachIndexed{index,item->
println("$index -> $item")
}
Kotlin集合相关
fun collectionType(){
//不可变集合
val stringList = listOf("one","two","three")
println(stringList)
val stringSet = setOf("one","two","three")
println(stringSet)
//可变集合
val num= mutableListOf(1,2,3,4,5)
num.add(6)
num.removeAt(1)
num[0] = 0
println(num)
//mutableSetOf 会移除元素里面相同的项
val hello = mutableSetOf("H","e","l","l","o")
hello.remove("o")
println(hello)
//集合的加减操作
hello+=setOf("w","o","r","l","d")
println(hello)
//Map<K,V> 不是Collection 接口的继承者,但是它是Kotlin的一种集合类型
val numberMap:Map<String,Int> = mapOf("key1" to 1,"key2" to 2,"key3" to 3)
println("All Keys:${numberMap.keys}")
println("All values:${numberMap.values}")
if("key2" in numberMap) println("Value by key Kye2:${numberMap["key2"]}")
if(1 in numberMap.values) println("1 is in the map")
if(numberMap.containsValue(1)) println("1 is in the map2")
//2个具有相同键值对,但顺序不同的Map相等,无论键值对的顺序如何,包含相同键值对的2个Map是相等的
val numberMap2 = mapOf("key2" to 2,"key3" to 3,"key1" to 1)
println("numberMap2 == numberMap : ${numberMap2 == numberMap}")//true == 等价于equals方法
println(numberMap.equals(numberMap2))
//2个具有相同元素的,但顺序不同的list相等吗?为什么?
val num2 = mutableListOf(2,1,3,5,4)
println("num == num2 : ${num == num2}")//false
}
上面代码执行的结果如下
[one, two, three]
[one, two, three]
[0, 3, 4, 5, 6]
[H, e, l]
[H, e, l, w, o, r, d]
All Keys:[key1, key2, key3]
All values:[1, 2, 3]
Value by key Kye2:2
1 is in the map
1 is in the map2
numberMap2 == numberMap : true
true
num == num2 : false
集合排序
fun collectionSort(){
val num = mutableListOf(1,5,3,4,2)
num.shuffle()//随机排序
println(num)
num.sort()//从小到大
println(num)
num.sortDescending()//从大到小
println(num)
data class Language(var name:String,var score:Int)
//单条件排序
val languageList:MutableList<Language> = mutableListOf()
languageList.add(Language("kotlin",10))
languageList.add(Language("C",8))
languageList.add(Language("java",10))
languageList.add(Language("B",8))
languageList.add(Language("swift",6))
languageList.sortBy{it.score}
println(languageList)
//多条件排序
languageList.sortWith(compareBy(
{it.score},{it.name}
)
)
println(languageList)
}
2,Kotlin的方法
普通方法,工具类等
fun main() {
println("普通方法 ${funDay(99)}")
println("普通方法2 ${fun2Day(99)}")
Person().test1()
Person.test2()
println("Util.double(2) : ${Util.double(2)}")
}
//普通方法
fun funDay(days:Int):Boolean{
return days>100
}
// 单表达式方法,当方法返回单个表达式时,可以省略花括号并且在 = 符号之后指定代码体即可, 效果同上
fun fun2Day(days:Int):Boolean = days>100
//普通类
class Person {
fun test1(){
println("test1 成员方法")
}
companion object{
fun test2(){
println("companion object 实现类方法,类似java的静态方法")
}
}
}
//工具类
object Util{
fun double(num : Int):Int{
return 2*num
}
}
Lambda表达式
fun main() {
lb()
println("1+3= ${testLb(1,3)}")
println("--1+3= ${tlb1(1,3)}")
println("---1+3= ${tlb2(1,3)}")
tlb3()
lb2()
}
val lb = {println("lambda 无参数")}
fun testLb(a:Int,b:Int):Int{
return a+b
}
val tlb1:(Int,Int) -> Int = {a,b -> a+b}
val tlb2 = {a:Int,b:Int -> a+b}
//tlb1 等价于 tlb2
fun tlb3(){
val arr = arrayOf(1,2,3,5,6)
println("filter输出第一个大于4的数据: ${arr.filter{it>4}.component1()}")
println("打印低于5的列表数据:${arr.filter{it<5}}")
}
//lambda可以通过_来替代不需要的参数
fun lb2(){
val map = mapOf("key1" to 1,"key2" to 2)
map.forEach{(key,value)->
println(value)
}
map.forEach{(_,value)->
println(value)
}
}
执行结果为:
lambda 无参数
1+3= 4
--1+3= 4
---1+3= 4
filter输出第一个大于4的数据: 5
打印低于5的列表数据:[1, 2, 3]
1
2
1
2
Lambda高阶函数
需求1:实现一个能够对集合元素进行求和的高阶函数,并且每遍历一个集合元素要有回调
需求2:实现一个能够对集合元素进行求和的高级函数,并返回一个声明为(scale:Int)-> Float 的函数
fun main() {
val list = listOf(1,2,4)
val result = list.sum{println("it:${it}")}
println("result:${result}")
println("result*2:${list.toIntSum()(2)}")
}
//高阶函数,函数作为参数
//需求1:实现一个能够对集合元素进行求和的高阶函数,并且每遍历一个集合元素要有回调
fun List<Int>.sum(callback:(Int)->Unit):Int{
var result = 0
for(v in this){
result+=v
callback(v)
}
return result
}
//函数作为返回值
//需求2:实现一个能够对集合元素进行求和的高级函数,并返回一个声明为(scale:Int)-> Float 的函数
fun List<Int>.toIntSum():(scale:Int)->Float{
println("first Layer")
return fun(scale):Float{
var result = 0f
for(v in this){
result+= v.toInt()*scale
}
return result
}
}
/**输出结果
* it:1
* it:2
* it:4
* result:7
* first Layer
* result*2:14.0
*/
闭包
能够读取其他方法内部变量的方法,是方法内部和外部链接起来的桥梁
特性: 方法可以作为另一个方法的返回值或参数,还可以作为一个变量的值 方法可以嵌套定义,即在一个方法内部可以定义另外一个方法
好处:
- 加强模块化
- 抽象
- 灵活
- 简化代码
实战:实现一个闭包
需求:实现一个接受一个testClosure方法,该方法要接受一个Int类型的v1参数,同时能够返回一个声明为 (v2:Int,(Int)->Unit)的函数,并且这个函数能够计算V1和V2的和
fun main() {
testClosure(1)(2){
println("1+2= ${it}")
}
}
/** 闭包高阶函数
* 需求:实现一个接受一个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)
}
}
//结果:1+2=3
解构声明
data class Result(val msg :String,val code:Int)
fun test(){
var result = Result("success",0)
val (msg,code) = result
println("msg= ${msg},code=${code}")
}
//msg= success,code=0
方法字面值
在kotlin中,匿名方法和lambda表达式都是方法的字面值
fun literal(){
var temp:((Int)->Boolean)?=null
temp = {num -> (num > 10)}
println("temp(11): ${temp(11)}")
}
//temp(11): true
3,Kotlin的类与接口
构造方法
/**
* 主构造方法
*/
class KotlinClass constructor(name:String){
/**
* 次构造方法
*/
constructor(v:Int,name:String):this(name){
println("name1--$name")
}
constructor(b:Char,v:Int,name:String):this(name){
println("name2--$name")
}
}
继承和覆盖,属性GetSet方法
fun main(){
Cat(10)
Dog(5).eat()
println("School is open:${School().isOpen} and ${School().score}")
Test().test()
}
open class Animal(age:Int){
init{
println(age)
}
open fun eat(){}
open val foot:Int = 0
}
//派生类有主构造方法的情况
class Cat(age:Int):Animal(age){
}
//派生类无主构造方法的情况
class Dog:Animal{
constructor(age:Int):super(age)
override val foot:Int = 4
override fun eat(){
println("dog eat $foot")
}
}
/**
* 属性的声明
*/
class School{
val name:String="Middle"
val numSudent:Int = 1000
val isOpen:Boolean
get() = numSudent > 900
var score:Float = 0.0f
get()= if(field<0.2f) 0.2f else field * 1.2f
set(value){
println(value)
}
}
class Test{
lateinit var school:School
fun setUp(){
school = School()
}
fun test(){
if(::school.isInitialized) {
println(school.isOpen)
}else{
println(false)
}
}
}
/**返回结果
* 10
* 5
* dog eat 4
* School is open:true and 0.2
* false
*/
抽象类
abstract class Printer{
abstract fun print()
}
class FilePrinter:Printer(){
override fun print(){
println("print file")
}
}
接口
//kotlin和java的接口定义区别,kotlin可以在接口里面做方法实现
interface Study{
fun discuss()
fun learnCourses(){
println("learn^")
}
}
class StudyA:Study{
override fun discuss(){
println("discuss")
}
}
继承多个接口里面有相同的方法,怎么复写?
//继承多个接口里面有相同的方法,怎么复写?需要在super后面添加参数接口
interface A{
fun foo(){
println("A")
}
}
interface B{
fun foo(){
println("B")
}
}
class D:A,B{
override fun foo(){
super<A>.foo()
}
}
数据类
数据类是一个简单的类,用于保存数据/状态并包含标准功能(函数)。 data关键字用于将类声明为数据类。
//数据类内部有以下函数,它消除了反复套用的代码
equals(): Boolean
hashCode(): Int
toString(): String
component() 函数对应的属性
copy()
- 包含具有至少一个参数的主构造函数。
- 主构造函数的参数标记为val或var。
- 数据类不能是抽象的,内部的,开放的或密封的。
- 在1.1版本之前,数据类只实现接口。1.1版本之后,数据类可以扩展其他类。
class Product1(var item: String, var price: Int)
data class Product2(var item: String, var price: Int)
fun main(agrs: Array<String>) {
val p1 = Product1("Thinkpad", 5000)
val p2 = Product1("Thinkpad", 5000)
println(p1==p2)
println(p1.equals(p2))
val d1 = Product2("Thinkpad", 5000)
val d2 = Product2("Thinkpad", 5000)
println(d1==d2)
println(d1.equals(d2))
}
//false
//false
//true
//true
对象表达式
class Shop2{
var address:Address2 ?= null
fun addAddress(address2:Address2){
this.address = address2
}
}
fun Test3(){
Shop2().addAddress(object:Address2("Kotlin test"){
override fun print(){
super.print()
}
})
}
工具类
//工具类
object DataUtil{
fun<T> isEmpty(list:ArrayList<T>):Boolean{
return list?.isEmpty()?:false
}
}
fun testUtil(){
val list = arrayListOf("12")
println(DataUtil.isEmpty(list))
}