因为书是实体书,所以很多内容复制了这篇:快速入门kotlin编程(精简但全面版)-CSDN博客

基本语法

变量

kotlin没有基本数据类型,使用对象类型 Int,Long,Short, Float,Double,Boolean,Char,Byte。

不声明类型(kotlin存在类型推导机制)。使用val定义不变的变量(相当于final修饰),用var修饰可变变量

函数

fun 函数名(变量1:类型,变量2:类型):返回值类型

fun sum (a:Int,b:Int):Int{
    return a+b
}

如果函数体只有一行代码的时候可以简写成

fun 函数名(变量1:类型,变量2:类型):返回值类型=函数体 (返回值类型也可以省略)

fun sum (a:Int,b:Int):Int= a+b

判断语句

if

if语句必须要有else,不然会报错

fun max(a: Int, b: Int): Int {
    if (a > b)
        return a
    else
        return b
}

if也可以放到return里面

fun max(a: Int, b: Int): Int {
     return if (a > b)
        a
     else
        b
}

也可以写成一行

fun max(a: Int, b: Int)=if(a>b)a else b

when

适用于多个if-else if-else if-...-else 场景

fun getScore(n:String)=
    when(n){
        "A"->"优秀"
        "B"->"良好"
        else ->"不好"
    }
  • when后面可以不写形参

  • ->后面也可以用{}括起来写很多行

适用于参数检查场景

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

循环

while

和java完全一致

for-in

for (i in list){
    //...
}

for (i in 0..10){
    //...
}

类和对象

定义

  1. 创建类的时候选择 Kotlin Class/File 文件

  2. 输入类名

  3. 在类里面定义变量、方法等等

class Person {
    var name = ""
    var age = 0
    fun pringInfo() {
        println(name + "的年龄是" + age)
    }
}

     4. 调用的时候省去了new关键字

fun main() {
    //去掉了new关键字
    val person = Person()
    person.name = "lyx"
    person.age = 24
    person.pringInfo()
}

继承

Kotlin中任何一个非抽象类默认都是不可以被继承的,相当于Java中给类声明了final 关键字。如果需要让一个类可以被继承,需要使用open关键字

open class Person {
    var name = ""
    var age = 0
    fun pringInfo() {
        println(name + "的年龄是" + age)
    }
}

构造函数

主构造函数

特点:没有函数体,直接定义在类名的后面

每个类默认都会有一个不带参数的主构造函数

也可以显式地给它指明参数

class Student(val id: String, val grade: Int) : Person(name,age) {
    //
}

如果主构造函数的逻辑需要特殊处理,Kotlin提供了init结构体,主构造的逻辑可在init中处理

open class Person(val name :String,val age :Int) {
    init {
        println("name is" + name)
        println("age is" + age)
    }
}
次构造函数

任何一个类只能有一个主构造函数,但是可以有多个次构造函数。

次构造函数的特点是:

  • 有函数体

  • 当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(包括间接调用)

  • 是写在类里面

class Student(name: String, age: Int, val id: String, val grade: Int) : Person(name, age) {
    // 三个参数
    // this关键字调用了主构造函数,this里面写默认值
    constructor(name: String, age: Int, id: String) : this("", 0, "", 0) {
    }
​
    // 无参构造
    //this关键字调用刚才定义的第一个次构造函数
    constructor() : this("", 0, "", 0) {
    }
}

接口

接口的定义

interface Study {
    fun study()
    fun eat()
}

接口的实现

class Student : Person ,Study{
    //Kotlin中使用override关键字来重写父类或者实现接口中的函数
    override fun study() {
        TODO("Not yet implemented")
    }
​
    override fun eat() {
        TODO("Not yet implemented")
    }
}

Kotlin支持接口方法的默认实现,方法有方法体默认实现,则继承类无需必须实现此方法

interface MyInterface {
    fun foo() {
        println("Interface default implementation")
    }
}

class MyClass : MyInterface // 未重写 foo()

fun main() {
    val obj = MyClass()
    obj.foo() // 输出: "Interface default implementation"
}

如果实现类中重写了接口方法,则优先执行实现类的重写方法。

interface MyInterface {
    fun foo() {
        println("Interface default implementation")
    }
}

class MyClass : MyInterface {
    override fun foo() {
        println("Class implementation")
    }
}

fun main() {
    val obj = MyClass()
    obj.foo() // 输出: "Class implementation"
}

权限修饰符

Javakotlin
public所有类所有类(默认)
protected当前类,子类,同一包下的类当前类,子类
default同一包的类(默认)x
private当前类当前类
internalx同模块下的类

数据类

在创建的时候选择Data class

数据类则只处理数据相关,与Java Bean类似,通常需要实现其getsethashCodeequalstoString等方法

data class UserBean(var id: Int, var name: String)

若无data关键字,上述方法(hashCodeequalstoString)无法正常运行

kotlin支持嵌套类,当某个类只服务于外部类,且没有独立存在的意义时可以使用嵌套类。

data class ActionInfo (
 
    val action: String?,
    var dataList: List<DataItem>?

) : Serializable{
    data class DataItem (var key: String, var value: Any?) : Serializable
}

单例类

在创建的时候选择Object

object Singleton {
    fun test(){
        println("===")
    }
}

在使用的时候

fun main(){
    Singleton.test()
}

Lambda

lambda是一小段可以作为参数传递的代码

集合的函数式API是用于入门Lambda编程的绝佳实例,所以先介绍Kotlin 集合的使用

//1.常规创建方式
val list1 =ArrayList<String>()
list1.add("a")
list1.add("b")

//2.listOf:不可变,只能查
val list2 =listOf<String>("a","b")
list2.add("c") //报错

//3.mutableListOf:可变
val list3=mutableListOf<String>("a","b")
list3.add("c")

//循环
for (value in list2) {
        println(value)
}

//set的创建,与list类似,使用的是setOf()和mutableSetOf()
val set1=setOf<Int,String>(1 to "a",2 to "b")

//map的创建
val map1 = HashMap<Int, String>()
map1.put(1, "1")
map1.put(2, "2")
// 赋值
map1[2] = "222"
// 访问
println(map1[2])
println(map1.get(2))

// 不可变
val map2 = mapOf<Int, String>(1 to "1", 2 to "2")
// map2[2] = "222" //报错
​
// 可变
val map3 = mutableMapOf<Int, String>(1 to "1", 2 to "2")
map3[2] = "222"
​
// 循环
for ((key, value) in map3) {
   println("$key:$value")
}

格式

{ 参数名1: 参数类型, 参数名2:参数类型 -> 函数体 }
//最外层是大括号,如果有参数传入到Lambda表达式的话,还需要声明参数列表,列表结尾用->表示函数体的开始,函数体内可以任意编写代码,但不建议过长,函数体最后一行代码作为Lambda表达式的返回值

方法介绍

maxByOrNull():返回当前集合中...最大元素

map 映射:返回新集合,将集合中的元素映射成另一个值

filter过滤:返回新集合,将集合中的元素进行筛选

any:返回Boolean,集合中是否存在元素满足Lambda的条件,有则返回true,无则false

all:返回Boolean,集合中元素是否全部满足Lambda的条件,有则返回true,无则false

示例

比如要找到列表中长度最长的元素

fun main() {
    val list = listOf<String>("aa", "dededed", "ajd", "aa")
​
    // 返回当前list中xx最大的元素
    // (1)不使用maxByOrNull函数
    var maxStr = ""
    for (str in list) {
        if (str.length > maxStr.length) {
            maxStr = str
        }
    }
    println("list中最大的str:" + maxStr)
​
    // (2)使用maxByOrNull函数
    // maxByOrNull或者maxBy是一个普通的方法,参数是Lambda参数
    var lambda = { str: String -> str.length }
    var maxString = list.maxByOrNull(lambda)
    println("list中最大的str:" + maxString)
    
    // 直接当成参数传递
    var maxString1 = list.maxByOrNull({ str: String -> str.length })
    // 如果lambda是方法的最后一个参数,参数可以提出来
    var maxString2 = list.maxByOrNull() { str: String -> str.length }
    // 如果只有一个参数,且是lambda参数,可以去掉方法的()
    var maxString3 = list.maxByOrNull { str: String -> str.length }
    // 有类型推导机制,也可以去掉参数类型
    var maxStrinf4 = list.maxByOrNull { str -> str.length }
    // 如果lambda只有一个参数,可以用it代替
    var maxString5 = list.maxByOrNull { it.length }
​
    // map映射(将集合中的每个元素都映射成一个另外的值)
    var newList1 = list.map { it.toUpperCase() }
    // filter过滤
    var newList2 = list.filter { it.length > 5 }
    // any 判断是否存在满足条件的元素
    var isAny = list.any { it.length > 5 }
    // all 判断是否全部满足条件
    var isAll = list.all { it.length > 0 }
}

Java函数式接口的使用

kotlin调用Java的方法,如果方法只接收一个Java单继承方法接口参数,可以使用函数式接口

单继承方法接口:就是接口中只有一个方法,比如Runnable接口:

public interface Runnable {
    void run();
}

在Java中启动一个线程:

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

在kotlin中

// Kotlin摒弃了new,若想声明匿名内部类,必须使用object
Thread(object :Runnable{
    override fun run() {
        print("aaa")
    }
}).start()
​
// Runnable类中只有一个待实现方法,即使这里没有显式地重写run()方法,Kotlin也能自动明白Runnable后面的Lambda 表达式就是要在run()方法中实现的内容
Thread(Runnable {
    print("aaa")
}).start()
​
// 如果一个Java方法的参数列表中有且仅有一个Java单抽象方法接口参数,可以将接口名进行省略
Thread({
    print("aaa")
}).start()
​
// Thread只需一个参数,可省略()
Thread {
    print("aaa")
}.start()

空指针判断

如果有特殊用处,函数的入参可空的时候,使用?表示可空

fun main() {
    study(null)
}
// ? 表示参数可以为空,
fun study(study: Study?) {
    // 此时这里会报错
    study.eat()
}

如果参数可为空的话,则此对象调用的方法必须要保证对象不为空,上面代码没有保证,则报错,修改如下

fun main() {
    study(null)
}
// ? 表示参数可以为空,
fun study(study: Study?) {
    if (study != null) {
        study.eat()
    }
}
  • ?.

表示?前面的不为空,才会执行.后面的方法,

如果为空,就什么都不做

fun study(study: Study?) {
    study?.eat()
}
  • ?:

表示?前的不为空,才返回?前的值,否则返回?后的值

val c = a ?: b
fun getTextLength(text: String?) = text?.length ?: 0
  • !!

可以强行通过编译,但如果对象为空,会抛出空指针异常

fun study(study: Study?) {
    study!!.eat()
}

let

fun study(study: Study?) {
    // ?.保证了study不为空,才会执行let函数
    study?.let {
        it.eat() // it是study
        it.drink()
    }
}

全局变量判空

因为全局变量的值随时都有可能被其他线程所修改,所以做了判空处理也无法保证没有空指针风险

var str: String? = null
fun demo() {
    //有问题
    if (str != null) {
        str.toUpperCase()
        str.reversed()
    }
}
fun demo1() {
    //使用let规避风险
    str?.let {
        it.toUpperCase()
        it.reversed()
    }
}

内嵌表达式

java中使用+连接 kotlin中使用$连接

fun main() {
    var name = "lyx"
    var age = 24
    println("姓名:$name,年龄:$age")
​
    // 复杂的: ${}
    var a = 2
    var b = 3
    println("a和b比较,${if (a > b) a else b} 大")
}

函数参数默认值

fun main() {
    // 正常传参
    myFun(1, "lisa")
    // 只传第一个,第二个参数有默认
    myFun(2)
​
    // 如果第一个参数有默认值,此时会报错,因为参数按照顺序放的
    // myFun1("lyx") //认为传入的是Int
​
    // kotlin使用键值对传参,不必按照参数定义的顺序来传参
    myFun1(name = "lyx")
}
// 第二个参数有默认值
fun myFun(id: Int, name: String = "nana") {
    println("$id:$name")
}
// 第一个参数有默认值
fun myFun1(id: Int = 4, name: String) {
    println("$id:$name")
}

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐