kotlin学习笔记

kotlin官方学习网站:https://developer.android.google.cn/kotlin/add-kotlin

.kt编译成.java

tools--->kotlin--->Show Kotlin Bytecode-->Decompile

.java转换成.kt

code--->Convert JavaFile to Kotlin File


Kotlin 基础语法

1.Var 与 Val

var 关键字: 可变变量
var <标识符> : <类型> = <初始化值>
// 可以改,可以读  get  set 如:var info1 : String = "A"

val 关键字: 不可变变量,只能赋值一次的变量(有一点点类似Java中final修饰的变量)
val <标识符> : <类型> = <初始化值>
// 只能读, 只有 get 如:val info2 : String = "B"

2.函数

//普通函数 返回类型  == 类型推导 Int
fun add2(number1: Int, number2: Int) = number1 + number2

// 可变参数 (可变长 参数函数)vararg关键字
fun lenMethod(vararg value: Int) {
    for (i in value) {
        println(i)
    }
}

3.字符串模板

 // $ 表示一个变量名或者变量值

 // $varName 表示变量值

 // ${varName.fun()} 表示变量的方法返回值

4.NULL检查机制

  // Kotlin的空安全设计对于声明可为空的参数,在使用时要进行空判断处理,
  // 有两种处理方式,字段后加!!像Java一样抛出空异常,
如:var info: String? = null    println(info!!.length)//!! 我自己负责info 不会为null ==  (不管null不null必须执行)  ==  Java
     另一种字段后加?
如:var info: String? = null    println(info?.length)  // ? 如果info是null,就不执行 .length


 // ?:  如果值为null  就输出设置的字符串  “你很牛逼”
如: var info: String? = null
    println(info?.length   ?: "你很牛逼")//打印值为:你很牛逼

5.区间

// 1 到 9
    for (i in 1..9) {
        // println(i)
    }

    // 不会输出
    for (i in 9..1) {
        // println(i)
    }

    // 大 到 小
    for (i in 9 downTo 1) {
        // println(i)
    }

    // 用区间做判断
    val value = 88
    if (value in 1..100) {
        // println("包了 1 到 100")
    }

    // 步长指定
    for (i in 1..20 step 2) {
        // 1 3 5 7 ...
        // println(i)
    }

    // 排除 最后元素
    for (i in 1 until 10) {
        println(i)
    }

6.内联函数

参考:Kotlin之inline(内联)_kotlin inline-CSDN博客

  • inline

在使用高阶函数(特别是函数的参数类型为函数类型)的时候一般加上inline,因为我们定义一个高阶函数后 没有办法去全面考虑其调用处是否会出现在循环当中

  • noinline

在内联函数中,某个函数参数不需要被内联时,使用noinline

  • crossinline

集合

1.List集合

val list = ArrayList<String>()
list.add("Apple")
list.add("Banana")
list.add("Orange")
list.add("Pear")
list.add("Pear")
list.add("Grape")

列表初始化:

val list2 = listOf<String>("Apple", "Banana", "Orange", "Pear", "Grape")

遍历操作:

for (fruit in list2) {
    println(fruit)
}

内置函数**listOf() & mutableListOf() **

listOf() 函数: 创建的是一个不可变集合(即,只能用于读取,无法进行添加、修改、删除操作

mutableListOf() : 创建的是一个可变集合(可添加删除和修改

2. Set集合

val set = setOf("Apple", "Banana", "Orange", "Pear", "Grape")
for (fruit in set){
    println(fruit)
}

和List集合基本一致,不同的是:Set是不可以放重复元素(会去重)

3. Map集合

val map = HashMap<String, Int>()
map.put("Apple", 1)
map.put("Banana", 2)
map.put("Orange", 3)
map.put("Orange", 4)
map.put("Orange", 5)
println(map["Orange"])  

map出现重复的键时,以最新的为准

遍历:

for((fruit, map) in map) {
    println("fruit: $fruit $map")
}

并且只允许存在最新的那个键值对

推荐使用以下方法来初始化Map元素:

val map = HashMap<String, Int>()
map["Apple"] = 1
map["Banana"] = 2

读取:

val number = map["Apple"]

mapOf()和 mutableMapOf()

val map2 = mapOf("Apple" to 1, "Banana" to 2, "Orange" to 3, "Pear" to 4, "Grape" to 5)
for((fruit, num) in map2) {
    println("fruit: $fruit $num")
}

二者区别同listOf() & mutableListOf() ,mapOf()是不可变的,mutableMapOf()是可变的

而mapOf() 的to并不是关键字,而是一个infix函数

4. 集合的函数式API语法结构

需求:找到list集合中单词长度最长的水果

val list4 = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
var maxLengthFruit = ""
for(fruit in list4) {
    if(fruit.length > maxLengthFruit.length) {
        maxLengthFruit = fruit
    }
}
println("max length fruit is $maxLengthFruit")

使用函数式API

val list4 = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
// 使用函数式API
var maxLengthFruit = list4.maxBy { it.length }
println("max length fruit is $maxLengthFruit")
{参数名1: 参数类型, 参数名2:参数类型 -> 函数体}
val list4 = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
var lambda = {fruit : String -> fruit.length}
var maxLengthFruit = list4.maxBy(lambda)

以上是未简化的lambda表达式

简化1:Kotlin规定,Lambda参数是函数最后一个参数时, 可以把Lambda表达式移到函数括号外面:

var maxLengthFruit = list4.maxBy(){fruit : String -> fruit.length}

简化2:Lambda参数时函数的唯一一个参数的话,可以省略括号:

var maxLengthFruit = list4.maxBy{fruit : String -> fruit.length}

简化3:Kotlin的类型推导机制,可以不用声明参数类型

var maxLengthFruit = list4.maxBy{fruit -> fruit.length}

简化4:当Lambda表达式的参数列表只有一个参数时,不必声明参数名,可以用it关键字代替

var maxLengthFruit = list4.maxBy{it.length}

完毕

同样Java的函数式API(单抽象方法接口为参数)也可以有以上的简化过程

new Thread(new Runnable() {
 @Override
 public void run() {
 System.out.println("Thread is running");
 }
}).start();

转Kotlin:

Thread(object : Runnable {
    override fun run() {
        println("Thread is running")
    }
}).start()

简化1:省略run方法(因为Runnable接口只有一个方法)和参数类型

Thread(Runnable {
    println("Thread is running")
}).start()

简化2:省略接口名

Thread({
    println("Thread is running")
}).start()

简化3:Lambda方法是最后一个参数,可以提到括号外面,同时如果该参数数唯一参数,省略括号

Thread{
    println("Thread is running")
}.start()

image-20230311215003948

同理,控件的监听事件也可以如此法简化,最终结果:

button.setOnClickListener {
	TODO("sfsfs")
}

 比较与数组

1.比较两个值

    //比较值本身 == 等价 Java的equals    

    // 比较对象地址   === 


2.数组

 // 第一种形式
    val numbers = arrayOf(1, 2, 3, 4, 5, 6, 7, 8)
    println(numbers[0])
     println(numbers[7])
    for (number in numbers) {
       println(number)
    }

    // 第二种形式  value=0
    val numbers2 = Array(6,  {value: Int -> (value + 200) })
    for (value in numbers2) {
        println(value)   //打印值:200 201 202 203 204 205
    }

条件与控制

1.条件

 // 表达式 比 大小 最大值
    val maxValue = if (number1 > number2) number1 else number2

2.when运用

    /* val number = 5
     when(number) {
         1 -> println("一")
         2 -> println("二")
         3 -> println("三")
         4 -> println("四")
         5 -> println("五")
         else -> println("其他")
     }*/

    /*val number = 745
    when(number) {
        in 1..100 -> println("1..100")
        in 200..500 -> println("200..500")
        else -> println("其他")
    }*/

 循环与标签

1.for循环操作

 var items = listOf("apple", "banana", "kiwifruit")
    for (item in items.indices) {
        println("item at $index is ${items[index]}")
    }

/*打印
item at 0 is apple
item at 1 is banana
item at 2 is kiwifruit
*/

//或者


 for(item in items){
        println(item)
    }


/*打印
apple
banana
kiwifruit
*/


2.自带标签与系统标签

类与对象

1.父类子类 与 构造函数等

类: public final class Person 默认就是这样的,不能被继承,  可以加open就可以被继承了

Kotlin 中的一个类可以有一个主构造函数以及一个或多个次构造函数。主构造函数是类头的一部分:它跟在类名后。主构造函数可以省略constructor

open class Person(id: Int) // 主构造
{

    // 次构造
    constructor(id: Int, name: String) : this(id) {

    }

    // 次构造
    constructor(id: Int, sex: Char) : this(id) {

    }

    // 次构造
    constructor() : this(787) {

    }

}

如果构造函数有注解或可见性修饰符,这个 constructor 关键字是必需的,并且这些修饰符在它前面:

public class Customer @Inject constructor(name: String) { }

2.接口和抽象类

接口默认是 public abstract interface

interface Callback {

    fun callbackMethod() : Boolean

}

抽象类默认是 public abstract class.   // 抽象类,不能创建实例

abstract class Person : Callback , Callback2 {

    // 抽象方法 默认就是open(此处省略) 不能实例,必须继承实现
    abstract fun getLayoutID() : Int

   //抽象类中的普通方法默认是public final的,所以需要标明     
   open fun initView(){}
   fun initData(){}
}

3.data 与 object

不会再修改了,可以是使用val
get set 构造 equals hashCode toString,  copy
data class User(var id: Int, val name: String, val sex: Char)

object只实例一次   相当于 单例

object MyEngine {

    fun m() {
        println("M run")
    }

}

4.单例

派生 和 object 尽量选择 object,当需要传参数时用派生(companion)

单例写法1

class APIClient {

    private object Holder {
        val INSTANCE = APIClient()
    }

    //派生
    companion object {
        val instance = Holder.INSTANCE
    }

}

//调用
APIClient.instance

单例写法2

class NetManager2 {

    companion object {

        private var instance: NetManager2? = null

        // 返回值:允许你返回null
        fun getInstance(): NetManager2? {
            if (instance == null) {
                instance = NetManager2()
            }

            // 如果是null,也返回回去了
            return instance

            // 第二种补救: 我来负责 instance 肯定不为null
            // return instance!!
        }
    }


    fun show(name: String) {
        println("show:$name")
    }

}

fun main() {
    // 客户端 来做补救措施
    val netManager = NetManager2.getInstance()

    // 如果 netManager == null ,就不执行 .show("AAA")
    netManager?.show("AAA")
}

5.内部类和嵌套类

嵌套类:无法获取到外部类的引用

open class TestDemo {
 private var a:Int = 2

      class A{
          //这里报错了,嵌套类无法获取到外部类的引用
        var b:Int = a
    }

}

    内部类:添加上 inner 后是内部类,可以获取到外部类的引用

open class TestDemo {
 private var a:Int = 2
    
    inner class A{
        var b:Int = a
    }
    
}

6.Kotlin中的密封类与常规接口

参考链接:Kotlin中的密封类与常规接口

Kotlin中的密封类与枚举:有何不同?

  • 使用密封类:当你想表示一组固定的类型,并希望在编译时确保所有情况都被处理时(例如,用于在状态机中建模不同的状态)。

  • 使用接口:当你想定义多个类必须遵守的约定,而不强制执行严格的层次结构时(例如,用于定义不同类之间的共同行为)

  • 密封类和枚举类似,但每个都有自己的用例。密封类让我们定义一组带有自定义属性和方法的实例。另一方面,当处理不需要额外状态的类型时,枚举很有用。

7.重载函数

由于在Java中是没有默认值参数的概念,当我们需要从Java中调用Kotlin中的默认值重载函数的时候,必须显示的指定所有参数值。但是这个绝对不是我们想要,否则Kotlin就失去了重载的意义了不能和Java完全互操作。所以在Kotlin给出了另一个方案就是使用**@JvmOverloads**注解这样就会自动生成多个重载方法供Java调用。

///kotlin类
open class TestKotlinDemo {
    @JvmOverloads
    fun tt(int: Int = 0, string: String = "", string2: String = "") {
    }
}

///Java类
public class TestJavaDemo extends TestKotlinDemo{
    private void ttt(){
//下面是调用重载方法tt
        tt(2);
        tt(2,"4");
        tt(2,"4","5");
    }
}

8.修饰符

和 java 的大多数修饰符是一样的,但是java 默认为 private ,但是kotlin 中默认为 public ,并且 kotlin中没有 包可见,新添加的修饰符为 :internal ,表示只在模块内部可用。è¿éåå¾çæè¿°

  • 在kotlin 中 public 是不可以访问 低可见性 internal 的。
  • 另外还要注意的是 protected ,在java 中他的访问范围是 包中,但是在kotlin 中则是 局限到 类 或者子类中,
  • 类的扩展函数 是访问不到 private 和 protected 的。

9.初始化 init

初始化的代码可以放到以 init 关键字作为前缀的初始化块中。

open class InitTestDemo(name: String) {
    private val customerKey = name

    init {
        println("打印name:$name")
        println("打印customerKey:$customerKey")
    }
}

 扩展函数

扩展函数允许你向现有类型添加函数而不修改它们。这可以减少样板代码并使代码更直观。

例如,1.考虑一个用于检查字符串是否为强密码的扩展函数:

fun String.isStrongPassword(): Boolean {
    // 检查长度
    // 检查符号和数字
    // 检查强度
    // 检查其他内容
    // 返回结果
}

//当我们需要使用它时,代码变得更加清晰:
val isPasswordStrongEnough = userPasswordInput.isStrongPassword()

2.withNotNull — 判空扩展函数


inline fun <T : Any, R> T?.withNotNull(block: (T) -> R): R? {
    return this?.let(block)
}
//用法示例:
val nullableValue: String? = null
nullableValue.withNotNull { value ->
    // 只有在nullableValue不为空时才会执行此处的代码
}

3.notEmpty — 判断集合是否非空:简化了检查集合是否非空的过程

fun <T> Collection<T>?.notEmpty(): Boolean {
    return this != null && this.isNotEmpty()
}
//更简洁的写法:
fun <T> Collection<T>?.notEmpty(): Boolean {
    return this?.isNotEmpty() == true
}
//用法示例:
val list: List<Int> = emptyList()
if (list.notEmpty()) {
    // 只有在list不为空时才会执行此处的代码
}

4. toFormattedString — 格式化数字和日期:简化了格式化数字和日期的过程

fun Int.toFormattedString(): String {
    return NumberFormat.getInstance().format(this)
}

fun Long.toFormattedString(): String {
    return NumberFormat.getInstance().format(this)
}

fun Date.toFormattedString(): String {
    return SimpleDateFormat.getDateInstance().format(this)
}

//用法示例:
val number = 1000000
val formattedNumber = number.toFormattedString()

5.debounce — 延迟执行代码块

debounce扩展函数简化了延迟执行代码块的过程,直到距离上次执行代码块的时间超过指定的时间间隔

fun View.onClick(debounceDuration: Long = 300L, action: (View) -> Unit) {
    setOnClickListener(DebouncedOnClickListener(debounceDuration) {
        action(it)
    })
}

private class DebouncedOnClickListener(
    private val debounceDuration: Long,
    private val clickAction: (View) -> Unit
) : View.OnClickListener {
    private var lastClickTime: Long = 0

    override fun onClick(v: View) {
        val now = SystemClock.elapsedRealtime()
        if (now - lastClickTime >= debounceDuration) {
            lastClickTime = now
            clickAction(v)
        }
    }
}
//用法示例:
button.onClick(debounceDuration = 500L) {
    // 只有在距离上次点击已经过去500毫秒后才会执行此处的代码
}

6. toBitmap — 将Drawable转换为Bitmap

fun Drawable.toBitmap(): Bitmap {
    if (this is BitmapDrawable) {
        return bitmap
    }
    val bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    setBounds(0, 0, canvas.width, canvas.height)
    draw(canvas)
    return bitmap
}
//用法示例:
val drawable = ContextCompat.getDrawable(context, R.drawable.my_drawable)
val bitmap = drawable.toBitmap()

7.applyIf — 根据条件应用代码块:简化了仅在满足条件时将代码块应用于对象的过程

inline fun <T> T.applyIf(condition: Boolean, block: T.() -> Unit): T {
    return if (condition) {
        this.apply(block)
    } else {
        this
    }
}
//用法示例
val number = 5
val formattedNumber = number.applyIf(number > 10) {
    toFormattedString()
}

lambda表达式


fun main() {

    // () -> Unit    空参函数  并且 没有返回值  函数名=method01

    // TODO 定义没有问题,调用不行
  /*  var method01 : () -> Unit
    method01() // 不能调用  没有具体的实现

    var method02 : (Int, Int) -> Int//不能调用
    method02(9, 9)

    var method03: (String, Double) -> Any?//不能调用
    method03("Derry", 543354.4)

    var method04 : (Int, Double, Long, String ? ) -> Boolean//不能调用
    method04(1, 545, 3543, null)

    var method05 : (Int, Int) -> Int//不能调用
    method05(9, 9)*/

    // : (形参类型)
    // = {具体详情}

    // TODO 定义没有问题,调用OK ,因为有实现了
    var m06 : (Int, Int) -> Int = {number1, number2 -> number1 + number2}
    println("m06:${m06(9, 9)}")

    var m07 = { number1: Int , number2: Int -> number1.toDouble() + number2.toDouble()}
    println("m07:${m07(100, 100)}")

    var m08 : (String, String) -> Unit = {aString, bString -> println("a:$aString,  b:$bString")}
    m08("李元霸", "王五")

    var m09 : (String) -> String = {str -> str}
    println("m09:${m09("降龙十八掌")}")

    var m10 : (Int) -> Unit = {
        when(it) {
            1 -> println("你是一")
            in 20..30 -> println("你是 二十 到 三十")
            else -> println("其他的数字")
        }
    }
    m10(29)

    var m11 : (Int, Int, Int) -> Unit = { n1, n2, n3 ->
        println("n1:$n1, n2:$n2, n3:$n3")
    }
    m11(29,22,33)

    var m12 = { println("我就是m12函数,我就是我") }
    m12()

    val m13 = {sex: Char -> if (sex == 'M') "代表是男的" else "代表是女的"}
    println("m13:${m13('M')}")

    // 覆盖操作
    var m14 = {number: Int -> println("我就是m14  我的值: $number")}
    m14 = {println("覆盖  我的值: $it")}
    m14(99)

    // 需求:我想打印, 并且,我还想返回值,就是 我什么都想要
    var m15 = { number: Int -> println("我想打印: $number")
        number + 1000000//注意这里要换行
    }
    println("m15:${m15(88)}")
}



///下面是打印结果

m06:18
m07:200.0
a:李元霸,  b:王五
m09:降龙十八掌
你是 二十 到 三十
n1:29, n2:22, n3:33
我就是m12函数,我就是我
m13:代表是男的
覆盖  我的值: 99
我想打印: 88
m15:1000088

Process finished with exit code 0

参考:《Kotlin核心编程》笔记:面向对象-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值