Kotlin

package com.example.test02

import kotlin.math.max

fun main(args: Array<String>) {
    val a = 10 // 常量Int
    var aa = 10L // 变量Long
    var b = "string" // 变量string

    // if 语句有返回值
    b = if (a > 5) {
        println(">")
        ">"
    } else {
        println("<")
        "<"
    }

    b = when(a) {
        1 -> "1"
        2 -> {
            print("")
            "2"
        }
        else -> "3"
    }

    b = when {
        a > 0 -> "1"
        a > 10 && a % 2==0 -> "2"
        else -> "3"
    }

    // 循环 while 和java中相同
    var range = 0..10 // IntRange 变量
    for (i in 1..10) {
        println(i)
    }
    for (i in 1 until 10 step 2) { // 左闭右开区间,每次递增2
        println(i)
    }
    // for (i in 10 downTo 1 step 2)  [10, 1]每次递增2

    println("Hello")
}

// 可使用默认参数,使用时可省略靠后的参数,也可指定传参
fun function(param1:Int = 0, param2: String = " ") {
    return
}
fun getMax(num1: Int, num2:Int) : Int = max(num1, num2)

fun getMax2(num1: Int, num2: Int) = if (num1 > num2) num1 else num2

fun checkNumber(num: Number) {
    when (num) {
        is Int -> println("Int")
        is Double -> {
            println("Double")
        }
        else -> println("else")
    }
}

/************************** 面向对象(注意,类似java,每个类一个文件) *****************************/
/*
 * Kotlin 中有 主构造函数 和 次构造函数
 * + 主构造函数
 *   类名后的圆括号,其中的字段名用于赋值。默认为空
 *   在创建下方Student时必须传入参数 `val stu = Student("a123", 5)`
 *   继承时必须通过 () 指定调用的构造方法
 * + 次构造函数
 *   类内部的 init 代码块
 *   当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(包括间接调用)
 */
open class Clazz {
    var param1 = ""
    var param2 = 0

    fun info() {
        println("$param1 $param2")
    }
}
// 加上open后这个类才可以基础,默认不可以
open class Person(val name: String, val age: Int) {
    fun info() {
        println(name + " is " + age + "years old.")
    }
}
// Student 不可以被继承
// 构造时传入父类参数,再用于构造父类
// 主构造中传给父类的参数不能使用 var val,使用了就是自己的,不能传给父类
// 3种构造方法:
// val stu1 = Student()
// val stu2 = Student("123", 10)
// val stu3 = Student("123", 1, "123", 19)
class Student(val sno:String, val grade: Int, name: String, age: Int) : Person(name, age), Study {
    // 主构造函数的的函数体
    init {
        println("this is init function.")
    }
    // 次构造函数,必须调用主构造函数
    constructor(name: String, age: Int) : this("", 0, name, age) {

    }
    constructor() : this("", 0) {

    }

    override fun readBooks() {

    }
}
// 只有次构造函数,没有主构造函数
class Student2 : Person {
    constructor(name: String, age: Int) : super(name, age) {}
}
// 接口与java种几乎相同,类实现时使用 : 和继承一样
interface Study {
    fun readBooks()
    fun doHomework() {
        println("接口的默认实现")
    }
}

// 可见性修饰符有4种:public(默认)、private(当前类可见)、protected(当前类、子类可见)、internal(只对同一模块可见)

// 数据类,自动实现 equals() hashcode() toString() 等方法
data class Cellphone(val brand: String, val price: Double)

// 单例类
object Singleton {
    fun singletonTest() {
        println("singletonTest is called.")
    }
}

/****************************** Lambda ********************************/
// {参数名1: 参数类型, 参数名2: 参数类型 -> 函数体}
fun f() {
    val list = ArrayList<String>()
    list.add("Apple")
    list.add("Banana")
    list.add("Orange")

    val list2 = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
    val list3 = mutableListOf("Apple", "Banana", "Orange", "Pear", "Grape")

    val set = setOf("Apple", "Banana", "Orange", "Pear", "Grape")

    val map1 = HashMap<String, Int>()
    map1["Apple"] = 1
    map1["Banana"] = 2
    map1["Orange"] = 3
    map1["Pear"] = 4
    map1["Grape"] = 5

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

    val maxLengthFruit1 = list.maxBy({ fruit: String -> fruit.length })
    val maxLengthFruit2 = list.maxBy() { fruit: String -> fruit.length }
    val maxLengthFruit3 = list.maxBy { fruit: String -> fruit.length }
    val maxLengthFruit4 = list.maxBy { it.length }

    val newList5 = list.map { it.uppercase() }
    val newList6 = list.filter { it.length <= 5 }.map { it.uppercase() }
    
    val anyResult : Boolean = list.any { it.length <= 5 } // 是否有长度大于5的
    val allResult : Boolean = list.all { it.length <= 5 } // 是否全部长度大于5
}

/*************************** 空指针 **************************/
// 可以直接用 == 比较类和string,不需要equal方法
// 利用编译时判空检查的机制几乎杜绝了空指针异常
// 空指针异常的检查提前到了编译时期,如果我们的程序存在空指针异常的风险,那么在编译的时候会直接报错,
//     修正之后才能成功运行,这样就可以保证程序在运行时期 不会出现空指针异常了。
fun f2() {
    doStudy(null) // 报错,无法编译
    doStudy2(null) // 正确
}
fun doStudy(study: Study) { // 此时无法传入 null
    study.readBooks()
    study.doHomework()
}
fun doStudy2(study: Study?) {
    if (study != null) {
        study.doHomework()
        study.readBooks()
    }
    study?.readBooks() // 省略了 if-null 判断
    var c = study ?: " " //  val c = if (study != null) {study} else {" "}
}
fun getTextLength(text: String) = text?.length ?: 0

 

/****************************** 标准函数 let with run apply*********************************/
/*
let 主要配合 ?. 使用
obj.let { obj2 ->
 // 编写具体的业务逻辑
}
obj 作为lambda的参数传入
*/
fun doStudy3(study: Study?) {
    study?.let {
        it.readBooks()
        it.doHomework()
    }
}

/*
val result = with(obj : 任意类型) { // lambda表达式
 // 这里是obj的上下文
 "value" // with函数的返回值
}
*/
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val result = with(StringBuilder()) {
    // 整个Lambda表达式的上下文就会是这个StringBuilder对象
    append("Start eating fruits.\n")
    for (fruit in list) {
        append(fruit).append("\n")
    }
    append("Ate all fruits.")
    toString()
}
println(result)

/*
与with类似
val result = obj.run {
 // 这里是obj的上下文
 "value" // run函数的返回值
}
 */
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val result = StringBuilder().run {
    append("Start eating fruits.\n")
    for (fruit in list) {
        append(fruit).append("\n")
    }
    append("Ate all fruits.")
    toString()
}
println(result)


/*
与run类似apply函数无法指定返回值,而是会自动返回调用对象本身
val result = obj.apply {
 // 这里是obj的上下文
}
// result == obj
 */
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val result = StringBuilder().apply {
    append("Start eating fruits.\n")
    for (fruit in list) {
        append(fruit).append("\n")
    }
    append("Ate all fruits.")
}
println(result.toString())


/******************************* 定义静态方法 ****************************/
/*
1. @JvmStatic 注解
2. 顶层方法:那些没有定义在任何类中的方法,比如 main() 方法。
   顶层方法在kotlin中直接调用即可,无需包名、路径
   java调用时要使用 文件名.顶层方法() 调用,编译器自动生成一个与文件名同名的类
 */
class Util {
    fun doAction1() {
        println("do action1")
    }
    companion object {
        @JvmStatic // 只能加在单例类或companion object中的方法上
        fun doAction2() {
            println("do action2")
        }
    }
}
// Util.doAction2() 调用

延迟初始化

class MainActivity : AppCompatActivity(), View.OnClickListener {
    private lateinit var adapter: MsgAdapter // lateinit 延迟初始化:声明时不用赋值null,使用前赋值即可
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        if (!::adapter.isInitialized) { // ::adapter.isInitialized 返回是否已经初始化
            adapter = MsgAdapter(msgList)
        }
        ...
    }
}

密封类

fun getResultMsg(result: Result) = when (result) {
    is Success -> result.msg
    is Failure -> "Error is ${result.error.message}"
    // 如果使用 interface 定义Result,这里不得不再加一个else语句
    // 密封类及其所有子类只能定义在同一个文件的顶层位置,不能嵌套在其他类中,这是被密封类底层的实现机制所限制的。
}

拓展函数

在不修改源码的情况下给类添加方法:

fun ClassName.methodName(param1: Int, param2: Int): Int {
    return 0
}
// 给 String 多添加了一个方法
fun String.lettersCount(): Int {
    var count = 0
    for (char in this) {
        if (char.isLetter()) {
            count++
        }
    }
    return count
}

操作符重置

class Obj {
    operator fun plus(obj: Obj): Obj {
        // 处理相加的逻辑
    }
}

class Money(val value: Int) {
    operator fun plus(money: Money): Money {
        val sum = value + money.value
        return Money(sum)
    }
    operator fun plus(newValue: Int): Money {
        val sum = value + newValue
        return Money(sum)
    }
}

高阶函数

如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个函数,那么该函数就称为高阶函数

fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
    val result = operation(num1, num2)
    return result
}
fun plus(num1: Int, num2: Int): Int {
    return num1 + num2
}
fun main() {
    val num1 = 100
    val num2 = 80
    val result1 = num1AndNum2(num1, num2, ::plus)
    val result2 = num1AndNum2(num1, num2) { n1, n2 ->
        n1 - n2
    }
    println("result1 is $result1")
    println("result2 is $result2")
}

对应的java代码如下:

public static int num1AndNum2(int num1, int num2, Function operation) {
    int result = (int) operation.invoke(num1, num2);
    return result;
}
public static void main() {
    int num1 = 100;
    int num2 = 80;
    int result = num1AndNum2(num1, num2, new Function() {
        @Override
        public Integer invoke(Integer n1, Integer n2) {
            return n1 + n2;
        }
    });
}

内联函数

使用lambda都会创建一个匿名类,带来性能开销。使用内联减小开销,在编译时将字节码放到必要的地方。使用 inline 关键字即可。

inline fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
     val result = operation(num1, num2)
     return result
}

noinline与crossinline

// 只内联block1,不内联block2
inline fun inlineTest(block1: () -> Unit, noinline block2: () -> Unit) {
}

内联函数所引用的Lambda表达式中是可以使用return关键字来进行函数返回的,而非内联函数只能进行局部返回。
保证在内联函数的Lambda表达式中一定不会使用return关键字

委托

/**
 * 类委托,MySet 的函数实现全部委托由辅助对象实现
 */
class MySet<T>(val helperSet: HashSet<T>) : Set<T> {
    override val size: Int
        get() = helperSet.size
    override fun contains(element: T) = helperSet.contains(element)
    override fun containsAll(elements: Collection<T>) = helperSet.containsAll(elements)
    override fun isEmpty() = helperSet.isEmpty()
    override fun iterator() = helperSet.iterator()
}
// 类委托的简写方式,等于上面
class MySet<T>(val helperSet: HashSet<T>) : Set<T> by helperSet {
    fun helloWorld() = println("Hello World")
    override fun isEmpty() = false  // 可只单独重写某个方法
}


/**
 * 属性 p 由 Delegate 对象委托实现,
 * 调用p属性的时候会自动调用Delegate类的getValue()方法,
 * 当给p属性赋值的时候会自动调用Delegate类的setValue()方法
 */
class MyClass {
    var p by Delegate()
}
class Delegate {
    var propValue: Any? = null
    // 必须用 operator 声明
    operator fun getValue(myClass: MyClass, prop: KProperty<*>): Any? {
        return propValue
    }
    operator fun setValue(myClass: MyClass, prop: KProperty<*>, value: Any?) {
        propValue = value
    }
}

infix

A to B 等价于 A.to(B)

if ("Hello Kotlin".startsWith("Hello")) {
}
// 上面通过 infix 可简写,没有infix这就是一个String类的拓展函数
infix fun String.beginsWith(prefix: String) = startsWith(prefix)
if ("Hello Kotlin" beginsWith "Hello") {
}


if (list.contains("Banana")) {
}
// 等价于
infix fun <T> Collection<T>.has(element: T) = contains(element)
if (list has "Banana") {
}

 

posted @ 2022-12-31 23:30  某某人8265  阅读(81)  评论(0编辑  收藏  举报