Kotlin数据类型的介绍
Kotlin没有基本数据类型的包装类
var : 定义"可变"变量的关键字
val : 定义"不可变"变量的关键字(可以通过反射的方式来修改)
八大基本数据类型:
var b:Boolean = false //Boolean类型
var byte:Byte = 10//字节类型
var short:Short = 2//短整型
var int:Int = 20//整型
var long:Long = 40L//长整型
var char:Char = 'a'//字符类型
var float:Float = 1.1234567f//单精度浮点类型
var double:Double = 1.1234567//双精度浮点类型
Kotlin的自动类型推断:
- 智能类型推断和类型转换(开发时使用)
- Kotlin编译器会自动推断
- Kotlin不同的数据类型之间不能相互赋值,要先转换再赋值
var a = 10
var b1 = a+10
var c = "22"
类型转换:
var i = 10
var s = "10"
var s1 = s.toInt()
var i1 = i.toString()
字符串的介绍:
val name = "萝莉\n世界第一\n卡哇伊"
原样输出字符串:
val name2 ="""
?萝莉
世界第一
卡哇伊
""".trimIndent().trimMargin("?")//字符串去除空格
字符串比较:
val str1 = "abc"
val str2 = String(charArrayOf('a','b','c'))
比较值:
println(str1.equals(str2))
println(str1 == str2)
比较内存地址:
println(str1 === str2)
字符串切割:
val str3 =".萝-莉."
val result = str3.split(".","-")//切割字符串
println(result[1]+result[2])
获取前13个字符串:
val str4 = "D:/rj/谷歌浏览器下载/视频.mp4"
val result2 = str4.substring(0,13)
val result3 = str4.substring(0..12)//区间
val result4 = str4.substringBefore("谷")//把"谷"之前的截取出来
val result5 = str4.substringBeforeLast("谷")//把最后的"谷"之前的截取出来
val result6 = str4.substringAfter("谷")//把"谷"之后的截取出来
val result7 = str4.substringAfterLast("谷")//把最后的"谷"之后的截取出来
字符串的拼接:
fun createDiary(place: String): String {
val result1 = "你真是一个"+place+"啊!"//java的方式
val result2 = "你真是一个${place}啊!"//kotlin的方式( ${参数,函数,运算...} )
return result2
}
.
.
Kotlin元组数据的介绍
- 二元元组
//定义一个二元元组数据
val pair =Pair<String,Int>("萝莉",16)//等价于 val pair2 = "萝莉".to(16)
println(pair.first)//获取元组里的第一个数据
println(pair.second)//获取元组里的第二个数据
- 三元元组
//定义一个三元元组数据
val triple = Triple<String,Int,String>("萝莉",16,"广东广州")
println(triple.first)//获取元组里的第一个数据
println(triple.second)//获取元组里的第二个数据
println(triple.third)//获取元组里的第三个数据
.
.
Kotlin空值处理的运算符(Kotlin最大的优点)
- Int? : 表示定义可空类型
- a!!: 表示关闭空检查(不建议开发时使用)
- a?.toInt(): 表示空安全调用符 ( 等价于:if(str != null){str.toInt()}),返回可空类型
- ?:值: 表示else默认返回的值
可空变量类型:
val k:Int? = null
非空判断:
val age:String =null!!
空安全调用符:
val age2 =age?.toInt()?:-1
.
.
Kotlin运算符与java一样
注:
Kotlin里面每一个运算符对应一个方法,可以通过重写对应的方法实现运算符重载
.
.
Kotlin的区间(Kotlin新增的数据存储类型)
- 正向区间
//定义一个1~100的区间的三种方式
val range1 = 1..100//最常用的形式
val range2 = IntRange(1,100)
val range3 = 1.rangeTo(100)
- 反向区间
val range001 = range1.reversed()
常见的遍历区间的方式:
//方式1
for (i in range1) {
//i:表示区间里的每一项
println(i)
}
//方式2
range001.forEach {
//it:表示区间里的每一项
println(it)
}
.
.
Kotlin的数组介绍
定义数组:
val arr1 = arrayOf("22","33")
val arr2 = arrayOf(22,33)
val arr3 = arrayOf("22",33)
注: Kotlin会根据数组赋值的数据来自动推断数组的类型
定义8种基本数据类型数组
val arr01 = IntArray(10)//等价于 new int[10]
val arr02 = BooleanArray(2)//等价于 new BooleanArray[2]
val arr03 = ByteArray(2)//等价于 new BooleanArray[2]
val arr04 = ShortArray(2)//等价于 new BooleanArray[2]
val arr05 = CharArray(2)//等价于 new BooleanArray[2]
val arr06 = FloatArray(2)//等价于 new BooleanArray[2]
val arr07 = DoubleArray(2)//等价于 new BooleanArray[2]
val arr08 = LongArray(2)//等价于 new BooleanArray[2]
修改数组里的值(于java一样)
arr1[1] = "卡哇伊"
arr1.set(0,"萝莉")
查找数组的角标(返回元素对应的角标,没有则返回-1)
val index1=arr1.indexOf("卡哇伊")//第一个
val index2=arr1.lastIndexOf("卡哇伊")//最后一个
val index3 = arr1.indexOfFirst {
it.startsWith("卡")
}
println(index1)
常见的遍历区间的方式:
//方式1
for ((index,value) in arr1.withIndex()) {
println("index=${index} 值=${value}")
}
//方式2
arr1.forEachIndexed {
index, value ->
println("index=${index} 值=${value}")
}
.
.
Kotlin集合的介绍
- 可以自动扩展容量的数组----List
1. 创建只读集合
val list1 = listOf("3","1","2")
2. 可读可写
val list2 = mutableListOf("01","02","03","2","33","22","1010","01","02","33")
3. 向集合中添加元素
//参数1:添加的位置
//参数2:添加的内容
list2.add(1,"卡哇伊")
注: 不填写位置默认添加到最后,填写添加位置,原来元素在向后移动
4. 修改元素
list2[0] = "luoLi"
根据下标修改集合中的数据
5. 过滤集合中的元素
val find =list2.find {
it.startsWith("03") }//找到第一个含有prefix标记的值
val filterList1 =list2.filter {
it.startsWith("0") }//把集合中第一个字符含有prefix标记的所有元素找出来
val filterList2 = mutableListOf<String>()
list2.filterTo(filterList2,{
it.startsWith("0")})//把两个集合所有含有prefix标记的值,存放到另一个集合中
val filterList3=list2.filterIndexed {
index, s -> index%2==0 }//把集合中角标为偶数的元素找出来
6.对集合中的元素排序
val sortedList1= list1.sorted()//正序排序
val sortedList2 = list1.sortedDescending()//倒序排序
//按照字段进行排序
val listTest = listOf(Person("时崎狂三",16),Person("楪祈",18),Person("牧濑红莉栖",22),Person("结城明日奈",15))
val sortedList3= listTest.sortedBy {
it.age }//正序排序
val sortedList4= listTest.sortedByDescending {
it.age }//倒序排序
7. 对集合中的元素分组
val groupBy =list2.groupBy {
val first=it.substring(0,1)
when(first){
"0"->"0"
else -> "其他"
}
}
8. 拆分集合中的元素
val partition =list2.partition {
it.startsWith("0") }
println(partition.first)
println(partition.second)
9. 求集合中的最值
val max= list1.max()//最大
val min= list1.min()//最小
val max2= listTest.maxBy {
it.age }//字符比较
val min2=listTest.minBy {
it.age }//字符比较
10. 去除集合中的重复元素
val set = list2.toSet()
val myList1=list2.distinct()
val myList2=list2.distinctBy {
it.substring(0,1) }
11. 集合重新组合
val nameList= listTest.map {
it.name }
12. 集合中某元素相加
val age=listTest.sumBy {
it.age }
13. 遍历集合中的元素
nameList.forEach {
println(it)
}
- 元素不重复的数组----Set( HashSet )
1. 创建只读集合
val set1 = setOf("1","2","3","3")
2. 可读可写
val set2 = mutableSetOf("01","02","03")
3. 遍历集合
treeSet.forEach {
println(it)
}
- 通过复杂对象来查找另一个对象的关联数组----Map
1. 创建只读集合
val map1 = mapOf("中国" to "China","英国" to "England","美国" to "USA")
2. 可读可写
val map2 = mutableMapOf()
3. 遍历集合
//遍历key
val key=map1.keys
key.forEach {
println(it) }
//遍历值
val values = map1.values
values.forEach {
println(it) }
//遍历键值对
map1.forEach {
(k, v) ->
println("key=${k},value=${v}")
}
.
.
Kotlin的条件判断和循环语句的介绍
- 条件判断语句
if-else语句
fun Judge(a: Int,b:Int): Int {
//也支持java if的用法,但不支持三元算符---C=A>B ? 100 :200;
return if (a>b)a else b
}
Kotlin没有switch语句,when语句(类似于switch)
fun toDo(age:Int){
return when(age){
//in:表示在什么里面
//is: 表示如果是什么就怎样
1,2,3,4,5,6-> println("没有上上小学")
in 7..11-> println("正在上小学")
in 12..14->{
return println("正在上中学")
}
in 15..17->{
println("正在上高中学")
}
in 18..21->{
println("正在上高大学")
}
else ->{
println("正在上社会大学")
}
}
}
- 循环语句
for-in
注: Kotlin可以遍历字符串,Java不行
val str = "abcd"
//(c in str):表示遍历str里的每一个元素c
//step:步长
for (c in str) {
if (c=='卡'){
break//跳出整个循环
// continue//跳出这次循环
}
println(c)
}
//打印角标
for ((index,c) in str.withIndex()) {
println("index=${index}c=${c}")
}
forEach(高级for循环)
注: 无法使用break和continue
val str = "abcd"
str.forEach {
println(it)
}
//打印角标
str.forEachIndexed {
index, c ->
println("index=${index}c=${c}")
}
多层循环
注: 可以通过添加“ tag@ ” 来跳出某个循环
val str1 = "123"
val str2 = "abc"
tag@for (c1 in str1) {
tag2@for (c2 in str2) {
if (c1=='b'&& c2=='2'){
break@tag2
}
println("${c1}${c2}")
}
}
while和do-while
var a = 0
while (a<=100){
println(a)
a++
}
do {
println(a)
a++
}while (a<100)
.
.
Kotlin函数/方法的介绍
函数的定义
- 无参无返回
fun Myfun(){
println("你好!")
}
- 有参无返回
fun Myfun(name:String,age:Int){
println(name)
println(age)
}
- 无参有返回
fun getNum():Int{
return 1
}
- 有参有返回
fun Myfun(name:String):Int{
return name.length
}
支持函数嵌套
fun Father(){
fun Child1(){
println("Child-1")
}
fun Child2(){
println("Child-2")
}
Child1()//调用方法
Child2()//调用方法
}
函数体只有一行代码,可以省略return,返回值类型也不用写
fun add(a:Int,b:Int) = a+b
默认参数,和具名参数(对应java的方法的重载)
- 默认参数
fun sendRequest(path:String,method:String="GET"){
println("请求路径=${path},请求的类型=${method}")
}
//调用方法
sendRequest(method="GET",path="www.com")//具名参数;特点:不用在意参数的位置
- 可变参数(vararg关键字修饰可变参数)
//vararg a: Int----对应的类型是一个数组
fun jiaFa(vararg a: Int): Int{
var result = 0
a.forEach {
result+=it
}
return result
}
泛型函数声明
/*
* <T> :定义泛型
* (thing:T):使用泛型
*/
fun <T> parseType(thing:T): T? {
when(thing){
is Int->{
println("是Int类型")}
is String->{
println("是String类型")}
else->{
println("不知道什么类型类型")}
}
return null
}
中缀表达式(可以自定义操作符)
使用infix关键字,作用:让代码更加简洁易懂
使用条件 : 1.必须成员函数或扩展函数 2.必须只有一个参数 3.参数不能是可变参数或者默认参数
class Test{
infix fun sayHelloTo(name: String){
}
}
扩展函数(取代java的util类)
如: 对String类的IsEmpty()进行重写
/*
* 1.对String类扩展:fun String.函数名
* 2.扩展函数可以访问当前对象里面的字段和方法
* 3.相当于把myIsEmpty方法写入到String类中,但String类的子类不能复写这个方法
* */
fun String?.myIsEmpty():Boolean{
//this:表示当前对象
return this==null|| this.length==0
}
高阶函数(函数作为另一个函数的参数)
fun cacl(a:Int,b:Int,block:(Int,Int)->Int):Int{
return block(a,b)
}
//调用方法
var ab1 = cacl(10,10){
a, b -> a+b }//引用私有方法
println(ab1)
补充:
使用场景 :可以处理函数变量为空的情况下调用
val add = ::函数名//获取函数的引用
add.invoke(1010,10)//通过引用调用函数
lambda表达式
注: 返回值是最后一行
val add:(Int,Int)->Int = {
a,b -> a+b}
//调用匿名函数
println(add(20, 20))
Kotlin内置函数let、also、with、run、apply
.
.
Kotlin类的介绍
注: Kotlin中没有new关键字,使用初始化对象的时候不需要使用new
例如:
val myClass =FatherClass("萝莉",16,"123456")//定义一个对象并初始化
类的定义
注: kotlin的类都是final(私有)的,不能被继承,不能别外部调用
//open关键字:把类或者变量设置为public(公用)
open class FatherClass(){
//构造函数
var name =""
private set//作用:禁止外部调用set方法,变为私有方法
var age =1
private set(value) {
//给方法设置访问权限
if (value<150){
field = value
}
}
open var phone = ""
//次构造函数(类似于java的方法重载)
constructor(name:String,age:Int):this(){
this.name=name
this.age=age
}
constructor(name:String,age:Int,phone:String):this(name,age){
this.phone=phone
}
//构造函数的逻辑写在init里
/*
init {
...
}
*/
/*--------自定义功能的函数---------*/
open fun greeting(){
println("卡哇伊")
}
private fun add(){
println("add")
}
}
等价于
class FatherClass(var name:String,var age:Int){
//构造函数
//次构造函数(类似于java的方法重载)
constructor(name:String,age:Int,phonc:String):this(name,age)
/*--------自定义功能的函数---------*/
fun greeting(){
println("卡哇伊")
}
}
.
类的继承
注: 父类必须使用open关键字修饰才能被继承
class childClass:FatherClass(){
//继承属性
override var phone: String = "123456789"
override fun greeting() {
//super.greeting()//表示调用父类的方法
println("萝莉卡哇伊")
}
}
.
抽象类
抽象类的继承不需要open关键字,但里抽象类里的实现方法可以使用open关键字;抽象类里可以没有抽象方法和抽象属性;Java中抽象类不能有具体的方法实现
- 定义抽象类
abstract class Human{
abstract var color:String
abstract var language:String
//定义抽象方法
abstract fun eat()
open fun sleep(){
}
}
- 抽象类可以继承抽象类,并且是单继承
abstract class Human2:Human(){
open fun sleep2(){
}
}
- 抽象类的使用(只能继承一个抽象类,可以继承多个接口)
class ZhHuman: Human2(),RideBike,DriveCar {
override var num: String ="2233"
//给抽象类里的抽象属性赋值
override var color: String = "黄色"
override var language: String = "中文"
//实现抽象类里的抽象方法
override fun eat() {
println("使用筷子吃饭")
}
override fun sleep2() {
super.sleep2()
}
//实现接口里的方法
override fun ride() {
println("学会了骑自行车")
}
override fun drive() {
println("学会了开车了")
}
}
.
嵌套类和内部类
- 嵌套类
class OutClass{
var name01 = "22"
class myClass{
fun sayHello(){
}
}
}
- 内部类(inner关键字)
class OutClass2{
var name1 = "22"
inner class myClass{
var name2 = ""
fun sayHello(){
name2=this@OutClass2.name1
}
}
}
.
泛型类
泛型的作用:放任何类型,可以限制存放的类型
定义泛型类
//定义泛型类
/*
* <T> :定义泛型
* (thing:T):使用泛型
* <T:Fruit>:泛型上限
*/
open class Box<T>(var thing:T){
}
泛型类的使用
//定义抽象类
abstract class Fruit
//定义子类的时候使用泛型(继承泛型类)
class FruitBox(thing: Fruit):Box<Fruit>(thing)
//定义子类的时候不知道具体的类型,继续使用泛型(泛型类继承泛型类)
class SonBox<T>(thing: T):Box<T>(thing)
//泛型上限, 泛型只能是Fruit类型或者Fruit类型的子类
class SonBox2<T:Fruit>(thing: T):Box<T>(thing)
//使用泛型类
val box =Box<String,Int>("22")
println(box.thing)
泛型擦除
泛型擦除:在运行的时候编译器会把设置好的泛型的类型给擦除掉
//使用inline和reified关键字,类取消泛型擦除
inline fun <reified T>getType(thing: T){
var name = T::class.java.name//获取泛型的类型
println(name)
}
泛型类型投射
//泛型类型投射(就可以接受Fruit类型。即Fruit的子类的类型)
//使用out关键字,作用:接受当前类型或者子类,相当于java的 <? extends Fruit>
//使用in关键字,作用:接受当前类型或者子类或当前类型的父类,相当于java的 <? super Fruit>
fun setFruitList1(list:ArrayList<out Fruit>){
println(list.size)
}
fun setFruitList2(list:ArrayList<in Fruit>){
println(list.size)
}
//泛型的*号投射(可以接受任何类型)相当于java的<?>
fun setFruitList3(list:ArrayList<*>){
println(list.size)
}
.
枚举类(与java一样)
定义枚举类
enum class test02{
type1,
type2,
type3,
}
枚举类的使用
test02.type1//使用枚举
//遍历枚举里的元素
test02.values().forEach {
println(it)
}
.
数据类(相当于java的bean类)
作用: 只保存数据,没有其他任何逻辑操作,对应java的bean类
定义数据类
data class NewsData(var title:String,var desc:String,var imgPath:String,var content:String)
数据类的使用
val news = News("标题","简介","图片路径","内容")//等于val (title,desc,imgPath,content) = News("标题","简介","图片路径","内容")
println(news.title)//等于news.component1()
println(news.desc)
.
.
Kotlin接口的介绍
注:
- Kotlin接口里面字段不能实现
- Java接口里的方法不能实现,Kotlin可以
定义一个接口
interface RideBike{
fun ride()//定义没有实现的方法
}
interface DriveCar{
//权限
var num:String
fun drive()//定义没有实现的方法
fun add(){
println("33")
}
}
.
.
Kotlin的协程的介绍
添加协程的依赖库:
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.0'
协程的使用
- 使用launch关键字启动协程
suspend fun main(args: Array<String>)= coroutineScope {
//launch启动协程(无返回值)
val job=launch{
//取消协程(关闭协程)
withTimeout(10000){
MyTask()//任务内容
}
}
//job.cancel()//取消协程(关闭协程)
//job.isActive//判断协程是否活跃状态
//job.join()//串行执行
}
补充:
- launch是一个函数 协程需要通过launch函数启动
- launch前三个参数都是默认参数 参数值可以不指定
- 最后一个参数是函数类型 调用的时候通过lambda表达式接收
- launch函数的返回值是Job类型 就是协程的任务
- 协程参数:
- context: 协程上下文(协程执行的代码放在哪个 线程 或 线程池 里执行)
- start:状态
- async启动协程(有返回值)
suspend fun main(args: Array<String>)= coroutineScope {
val job2 = async {
MyTask2() }
//获取协程的返回值
job2.await()//通过await()可以获取协程执行完返回的数据
}
定义挂起函数
注:
- 挂起函数:可以被挂起执行;到时间之后从线程池中空闲的线程中恢复执行
- 挂起函数必须通过suspend进行修饰
注意 :挂起函数必须在协程中执行 或者 在其他挂起函数中执行
suspend fun MyTask(){
println("协程执行前的线程名:${Thread.currentThread().name}")
(1..10).forEach{
println("${it}")
delay(1000)//等待sleep() 非阻塞//挂起函数
}
println("协程执执行后的线程名:${Thread.currentThread().name}")
}
suspend fun MyTask2():String{
delay(1000)
return "MyTask2的返回值"
}
参考资料:
.
.
Kotlin实现单例模式
//object单例中使用字段都是静态,方法不是静态的
//缺点:里面的字段都是静态的,占内存
object Utils{
var name02 = "萝莉"
var age = 10
fun getName(){
println(name02)
}
}
实现与java类似的单例
class Utils2 private constructor(){
//使用构造方法 --- private constructor()
var name02 = "萝莉"
//伴生对象(需要在class中使用)
//作用:把属性设置为静态
companion object{
var age0 = 20
}
companion object{
var age = 20
val instance:Utils2 by lazy {
Utils2() }//作用:懒加载,只加载一次,是线程安全的
}
fun getName(){
println(name02)
}
}
补充:
懒加载(使用 by lazy 关键字)
条件: 必须是val修饰,返回值是最后一行代码,并且是线程安全的
特点: 使用的时候再初始化,并且只初始化一次
val name0:String by lazy {
"萝莉" }
延迟加载(使用lateinit关键字)
条件: 必须是var修饰
特点: 使用前一定要先赋值,再使用
lateinit var name00:String