kotlin 学习的小知识点

本文介绍了Kotlin中的多个进阶知识点,包括单例模式、常量定义、伴生对象、Intent使用技巧、列表操作、变量限定及数据类比较、全局变量创建、高阶函数、扩展函数、类型转换、数组遍历、函数类型别名定义等内容。
摘要由CSDN通过智能技术生成

1.单例模式

在Java中

public class Singleton{
		//私有化,杜绝被本类外的其他类使用;静态,在代码加载时就创建
        private static Singleton singleton = new Singleton();
        //构造器私有,其他类无法创建该类的对象
        private Singleton(){}
        //只能通过get方法获取该类的对象
        public static Singleton getSingleton() {
            return singleton;
        }
    }

在Kotlin中

object Singleton{
	//方法体1
	//方法体2
}

调用方式

Singleton.方法名()

2.定义常量的关键字const

只有在单例类、companion object或顶层方法中才可以使用const关键字

3.companion object(伴生对象)

类似java中的static

companion这个关键字实际上只是一个快捷方式,允许你通过类名访问该对象的内容(如果伴生对象存在一个特定的类中,并且只是用到其中的方法或属性名称,那么伴生对象的类名可以省略不写)。就编译而言,下面的testCompanion()方法中的三行都是有效的语句。

class TopLevelClass {
	//companion object修饰的类,类名可以不写,直接访问其中的方法
    companion object {  
        fun doSomeStuff() {
            ...
        }
    }
    //object修饰的类是单例类,需要通过类名访问其中的方法
    object FakeCompanion {
        fun doOtherStuff() {
            ...
        }
    }
}

fun testCompanion() {
    TopLevelClass.doSomeStuff()
    TopLevelClass.Companion.doSomeStuff()
    TopLevelClass.FakeCompanion.doOtherStuff()
}

4.startActivity和startActivityForResult中intent的区别

第一种情况:
代码中的intent调用的是父类的getIntent()方法,这个点击事件可以执行,启动的Activity也能收到消息

thirdly_3_3_4_bt.setOnClickListener {
            intent.putExtra("data","Hello,这个上一个Activity传来的消息")
            intent.setClass(this,FourthActivity::class.java)
            startActivity(intent)
        }

第二种情况:
intent调用的是父类的getIntent()方法,需要下一个Activity返回消息
可以启动下一个Activity,启动的Activity可以收到消息,但是无法返回消息

//FirstActivity
thirdly_3_3_4_bt.setOnClickListener {
			//不创建intent的对象,下一个Activity可以接收消息,无法返回消息
//            val intent = Intent() 
            intent.putExtra("data","Hello,这个上一个Activity传来的消息")
            intent.setClass(this,FourthActivity::class.java)
            startActivityForResult(intent,1)
        }
        
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when(requestCode){
            1 -> if (resultCode == RESULT_OK){
                val stringExtra = data?.getStringExtra("data")
                Toast.makeText(this, "收到请求码为$requestCode 回复:$stringExtra", Toast.LENGTH_LONG).show()
            }
        }
//FourthActivity
private fun initView() {
        fourth_activity_back_bt.setOnClickListener {
            intent.putExtra("data","fourthActivity返回的消息")
            setResult(RESULT_OK,intent)
            finish()
        }
    }

5.list赋值操作

  1. var list
var list = listOf("apple","orange") //只读,不能对list中的元素增删改
list = listOf("111","222","333")    //但是可以对list对象重新赋值
for (bean in list) println("list对象重新赋值"+bean)
list对象重新赋值111
list对象重新赋值222
list对象重新赋值333
var list = mutableListOf("apple","orange")//使用 mutableListOf定义list,可实现增删改查

2.val list

val list = listOf("apple","orange") //元素和list对象都是只读,都无法修改
list = listOf("111","222","333") //报错 ”Val cannot be reassigned“
  1. ArrayList定义的list与java中没有什么区别
var list1 = ArrayList<String >()//从源码可知,ArrayList定义方式为Java的定义方式
list1.add("tom")
list1.add("and")
list1.add("jerry")
list1[0] = "kity"
for (bean in list1) println(bean)

val list1 = ArrayList<String >()  //var和val定义的list两者都可以增删改查
list1.add("tom")
list1.add("and")
list1.add("jerry")
list1[0] = "kity"
for (bean in list1) println(bean)
kity
and
jerry
  1. java定义的list可以赋值给kotlin定义的list,反之则报错
var list = mutableListOf("")
var list1 = ArrayList<String >()
list = list1
var list = mutableListOf("")
var list1 = ArrayList<String >()
list1 = list //报错:Type mismatch: inferred type is MutableList<String> but kotlin.collections.ArrayList<String> /* = java.util.ArrayList<String> */ was expected

6.var,val在类中限定,以及两个数据类的对象如何认定相等的

例 1:
两个属性,data1主构造器赋值,data2定义时赋值

class datas(var data1:String ){
    var data2:String = "非构造参数"
}

fun main() {
    var ex1 = datas("构造参数")
//    ex1.data2 = "构造参数"
    println(ex1.data2)
    val ex2 = datas("构造参数")
    println(ex2.data2)
    println(ex1 == ex2)
}

打印结果:
默认对象的toString()打印的主构造器中的参数

非构造参数
非构造参数
false

例 2:
val修饰的变量和类的对象在赋值后不能再重新赋值了

data class datas(val data1:String ){
    val data2:String = "非构造参数"
}

fun main() {
    var ex1 = datas("构造参数")
    ex1.data1 = "构造参数1"
    ex1.data2 = "非构造参数2"
    println(ex1.data2)
    val ex2 = datas("构造参数")
    ex2 = ex1
    println(ex2.data2)
    println(ex1 == ex2)
}

结果:
报错 7,8,11行报错。

Val cannot be reassigned

如果在实际应用中,如果对象的属性需要重新赋值,用var修饰

实例化类的时候kotlin建议val修饰,如用var修饰不会报错,系统会提示:
variable is never modified andcan be declared immutable use “val”(变量永远不会被修改,可以使用"val"来声明它是不可变的)

例 3:
两个对象的主构造器中属性的值相等,属性data2值不相同
但是结果作为数据类这两个对象是相等的,这个是不是属于Kotlin的BUG?

data class datas(var data1:String ){
    var data2:String = "非构造参数"
}

fun main() {
    var ex1 = datas("构造参数")
    ex1.data2 = "非构造参数2"
    println("ex1.data2 = "+ex1.data2)
    val ex2 = datas("构造参数")
    println("ex2.data2 = "+ex2.data2)
    println("ex1是否等于ex2 ? " + (ex1 == ex2))
}

结果:

ex1.data2 = 非构造参数2
ex2.data2 = 非构造参数
ex1是否等于ex2 ? true

例 4:
如果类不用data修饰,定义为非数据类,则两个类就算属性相等,equals也是不相等的

class datas(var data1:String ){
    var data2:String = "非构造参数"
}

fun main() {
    var ex1 = datas("构造参数")
    val ex2 = datas("构造参数")
    println("ex1是否等于ex2 ? " + (ex1 == ex2))
}

结果:

ex1.data2 = 非构造参数
ex2.data2 = 非构造参数
ex1是否等于ex2 ? false

7.全局变量的创建

不建议使用

	//创建msg值为null的全局变量
    var msg : String ? = null 

建议使用

    //创建msg为全局变量,并稍后初始化
    lateinit var msg :String  
    //判断msg是否初始化
    if (!::msg.isInitialized){
            //TODO
        }

8.高阶函数

对高阶函数的理解:把一个函数作为参数传递到另一个函数中

不使用高阶函数时
提供B具体执行的代码
执行A:num1Andnum2函数
sum = num1 + num2
sum = num1 + num2
执行B:operation函数
结束
Lambad表达式

在执行A函数时,插入一段B代码,这段B代码是调用A函数时创建的。

fun main(){
    val num1 = 10
    val num2 = 20
    //插入的代码在调用的时候完成
    val result1 = num1Andnum2(num1,num2){n1,n2->n1+n2}
    val result2 = num1Andnum2(num1,num2){n1,n2->n1-n2}
    println(result1)
    println(result2)
}
//函数作为参数时,只需要定义好参数类型和返回值类型,返回值为空则为Unit
fun num1Andnum2(num1:Int,num2:Int,operation:(n1:Int,n2:Int)->Int): Int {
	//不使用高阶函数时,这段代码的功能就时返回两个数的和
    val sum = num1 + num2
    //使用高阶函数后,还可以让这个和做其他操作,但是这个其他操作可能在不同的地方有不同的操作,所以由operation参数来做个接口。在本例中,是做+10或-10操作
    val sum = operation(sum,10)
    return sum
}

9.内置扩展函数 lei/also run/apply with

use函数

  • 实现了Closeable接口的对象可调用use函数
  • use函数会自动关闭调用者(无论中间是否出现异常)
  • Kotlin的File对象和IO流操作变得行云流水
    链接

let/also函数

  • let可以配合可空性 “?”来使用,如果data=null 则不执行let内部代码,如果有返回值则直接返回null
  • 在let中,用it表示引用对象,并可调用其方法,it不可省略。
  • 返回值是语句块的最后一行的返回类型,若最后一行语句无返回值,则整个let语句块也无返回值
    let和also的区别:also返回对象本身,在本例中返回list对象
//在此例中,判断list是否为空,为空直接返回null,否则返回最后一行,如最后一行无返回值,则整个let语句无返回值,
       var result =  list?.let {
            it.add(1)
            it.add(2)
            it.add(3)
            "ok"
        }
//list后面没有?,则不判断list是否为空
        var result =  list.let {
            "ok"
        }

apply / with / run
作用基本相同,都是可以代替对象本身,直接调用对象的方法或者属性,区别则是使用时调用的方式不同,和返回的不同

返回对象本身
also:it
apply:this

返回最后一行的值
let:it
run:this

在这里插入图片描述

链接

10. 类型强制转换 as

  1. as不安全的类型强制转换,如果转换不成功则会抛出异常
val y = 123
val x: String = y as String
  1. as?安全的类型强制转换,转换不成功则赋值null,但是要注意x的类型也要为可空类型
val y = 66
val x: String? = y as? String
println("x = $x")   // x = null
在这里插入代码片

11.数组的遍历.withIndex

	val intArray = intArrayOf(9,8,7,6,5,4)
    for ((index,result) in intArray.withIndex()){
        println("第$index 个元素,值是:$result")
    }

12.定义函数类型的别名typealias

  1. 作用:如果函数类型在文件中编写次数较多,可以通过typealias 给这个函数类型定名字
    val sum = fun (a:Int,b:Int) = (a+b).toString()
    fun test(a:Int,b:Int,printlnIntSum:(Int,Int)->String){
        println(printlnIntSum(a, b))
    }
    test(1,2,sum)

示例中给函数类型(Int,Int)->String定义了名字sumToSting,以后在使用中就使用名字

//typealias 定义时在类的外部,和import在一起
typealias sumToSting = (Int,Int)->String
fun main() {
    val sum = fun (a:Int,b:Int) = (a+b).toString()
    fun test(a:Int,b:Int,printlnIntSum:sumToSting){
        println(printlnIntSum(a, b))
    }
    test(1,2,sum)
}

13.isEmpty()与null与“”的区别

isEmpty() 分配了内存空间,值为空,是绝对的空,是一种有值(值 = 空)
“”分配了内存空间,值为空字符串,是相对的空,是一种有值(值 = 空字串)
null 是未分配内存空间,无值,是一种无值(值不存在)

isEmpty()并不是String类型所特有的方法,ArrayList,HashMap,HashSet也同样拥有此方法,原因在于isEmpty()实际上是Collection中定义的方法,而所有继承了该接口的方法都将会实现。

--------------------------------------------------分割线----------------------------------------------------------------

1.类的修饰符

1.sealed class 密封类

为了限制出现以下代码的情况:

when的分支条件中必须增加无用的else分支(书中叙述)

//实际使用时,就算没有unknown分支也不会报错
interface Result
class Success (val msg : String = "success") : Result
class Failure (val msg : String = "failure") : Result

fun test(result: Result) {
    when(result){
        is Success -> println(result.msg)
        is Failure -> println(result.msg)
        else -> println("未知")
    }
}

为避免出现上述错误,使用sealed class代替interface

//书上说,密封类强制要求将每一个子类所对应的条件全部处理 但是一下这段代码没有报错,只是提示when下缺少unknown或者else的分支
sealed class Result
class Success (val msg : String = "success") : Result()
class Failure (val msg : String = "failure") : Result()
class Unknown (val msg : String = "unknown") : Result()

fun test(result: Result) {
    when(result){
        is Success -> println(result.msg)
        is Failure -> println(result.msg)
        //增加unknown或者else分支其中一个,就不会有提示
        //is Unknown -> println(result.msg)
		//else -> println("未知")
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值