Kotlin基础语法

需要补充学习内容:

  • Kotlin函数式API和Java的函数式API

前言

在线运行Kotlin代码的网站:https://try.kotlinlang.org
总结自: <<第一行代码(第三版)>>

最重要的是: 时隔将近一年,俺又回来啦!虽然没人在意.

基础语法

1 变量和函数

1.1 变量

Kotlin 中定义一个变量,只允许在变量前声明两种关键字:val 和 var

  • val(value的简写)用来声明一个不可变的变量,对应 Java 中的 final 变量
  • var(variable的简写)用来声明一个可变的变量,对应 Java 中的非 final 变量

    Kotlin 中有出色的类型推导机制,可以推导出变量是什么类型。

注意: Kotlin 中每一行代码的结尾不加分号

Kotlin 的类型推导机制并不总是能正常工作,比如对一个变量延迟赋值,这时就需要显式地声明变量类型,语法如下所示:

val a: Int = 10;

这里的 Int 的首字母是大写的,表示 Kotlin 完全摒弃了 Java 的基本数据类型。

八种类型包括:Int、Long、Short、Float、Double、Boolean、Char、Byte

1.2 函数

语法规则如下:

fun methodName(param1: Int, param2: Int): Int {
    return 0
}

解释如下:

  • fun:声明函数的关键字
  • methodName:函数名,小驼峰命名
  • param1,param2:两个 Int 型的参数
  • Int:最后的 Int 表示返回值为 Int 类型

2 程序的逻辑控制

2.1 if

if 和 Java 中的没什么区别,但是比 Java 中多了一项功能:可以有返回值,返回值就是 if 语句每一个条件中最后一行代码的返回值。看个例子:

fun largerNumber(num1: Int, num2: Int): Int{
    var value = 0
    if (num1 > num2){
        value = num1
    } else {
        value = num2
    }
}
//可以简写成如下格式:
fun largerNumber(num1: Int, num2: Int): Int{
    var value = if (num1 > num2 ) {
        num1
    } else {
        num2
    }
}

语法糖:当一个函数只有一行代码时,可以省略函数体部分,直接将这一行代码使用等号串连在函数定义的尾部。那么对上述代码进行进一步的精简:

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

2.2 when

一个查询考试成绩的功能,输入学生姓名,返回学生成绩

fun getScore(name: String) = when (name) {
    "Tom" -> 87
    "Jim" -> 94
    "Jack" -> 84
    else -> 0
}

when 的格式如下:

匹配值 -> { 执行逻辑 }

when 还允许类型匹配,如下示例:

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

2.3 for 循环

用如下代码来表示一段闭区间 [0,10]

val range = 0..10

有了区间后,用 for-in 循环来遍历这个区间:

fun main() {
    for (i in 0..10) {
        println(i)
    }
}

左闭右开的区间 [0,10) 用如下方式表示:

val range = 0 until 10

如果想要跳过一些元素,可以用 step 关键字

fun main() {
    for (i in 0 until 10 step 2) {
        print(i+" ")
    }
}
//output: 0 2 4 6 8

还可以用关键字 downTo 创建一个降序区间

fun main() {
    for (i in 0 until 10 downTo 1) {
        print(i+" ")
    }
}
output: 9 8 7 6 5 4 3 2 1

3 面向对象

3.1 类与对象

声明一个类

class Person {
    //类体
}

实例化类:

val p = Person()

3.2 继承与构造函数

继承

声明一个可继承类

open class Person {
    //TODO
}

Kotlin任何一个默认非抽象类均不能被继承

继承该open类,继承关键字变成了一个冒号

class Student : Person() {
    //TODO,Person()是构造函数
}

主构造函数

主构造函数没有函数体,直接定义在类名的后面
主构造函数只能有一个
一个函数可以没有主构造函数(这种情况非常特殊,很少见,但是允许)

class Student(val sno: String, val grade: Int) : Person() {
    //TODO
}

进行实例化时,需要传入构造函数的所有参数

val student = Student("a123", 5)

如果显示的声明了父类的主构造函数体,那么在子类继承父类时需要传入相应的参数

open class Person(val name: String, val age: Int){
    //TODO
}
//继承Person
class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age){
    //TODO
}

次构造函数

当一个类中同时有主/次构造函数时,次构造函数必须调用主构造函数
次构造函数有函数体
关键字是: constructor
次构造函数可以有多个

class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age) {
    constructor(name: String, age: Int) : this("", 0, name, age) {
    }
    constructor() : this("", 0) {
    }
}

第一个次构造函数接收name和age两个参数,然后又通过this关键字调用了主构造函数,并将sno和grade两个参数赋初始值

第二个次构造函数不接收任何参数,它通过this关键字调用了第一个次构造函数,并将name和age参数赋初始值,这种调用方式是间接调用主构造函数

注意:需要关注的关键点是参数列表,第二个次构造函数this的参数列表对应的是第一个次构造函数

3.3 接口

接口与Java基本一致
不同的时,kotlin中类的继承和接口的实现都统一用冒号

JDK1.8之后和kotlin支持接口的默认实现

interface Study {
    fun doHomework() {
        println("do homework default implementation.")
    }
    fun Study() {}
}

现在,当一个类去实现Study接口时,指挥强制要求实现readBook函数,而doHomework函数可以自由选择实现或者不实现.

修饰符 Java Kotlin
public 所有类可见 所有类可见(默认)
private 当前类可见 当前类可见
protected 当前类,子类,同一包路径下的类可见 当前类,子类可见
default 同一包路径下的类可见(默认)
internal 同一模块中的类可见

3.4 数据类与单例类

MVC MVP MVVM 之类的架构模式,其中M指的就是数据类

数据类

数据类通常需要重写equals(),hashCode(),toString()这几个方法
其中equals()判断两个数据类是否相等.hashCode()方法作为equals()的配套方法也需要重写
toString()可以让输出log更加清晰

在Kotlin中,只需要在数据类前声明关键字data,Kotlin就会根据主构造函数中的参数自动生成equals(),hashCode()toString()等方法

data class Cellphone(val brand: String, val price: Double)
//注意在参数列表添加需要的参数

单例类

Java最常见的单例类

public class Singleton {
    private static Singleton instance;
    private Singleton() {};
    public synchronized static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
    
    public void singletonTest() {
        System.out.println("singletonTest is called.");
    }
}

在Kotlin中,只需要在类前面声明object关键字,那么就可以将该类变为单例类.

object Singleton {
    fun singletonTest() {
        println("singletonTest is called.")
    }
}

4 Lambda编程

4.1 集合的创建和遍历

List
创建一个集合

//正常创建一个集合并添加一些数据
val list = Arraylist<String>()
list.add("apple")
list.add("orange")
list.add("banana")

//kotlin提供了一个内置方法listOf()简化写法
val list = listOf("apple", "orange", "banana")

使用for-in进行循环遍历

fun main() {
    val list = listOf("apple", "orange", "banana")
    for (fruit in list) {
        println(fruit)
    }
}

注意: listOf()方法创建的是一个不可变的集合,无法对该集合进行添加,修改或者删除操作,只能读取.
如果需要创建一个可变的集合,那么使用mutableListOf()方法就可以了.

val list = mutableListOf("apple", "orange", "banana")

Set

Set集合与List集合类似,实际上就是将创建集合的方法换成了setOf()和mutableSetOf()方法
Set集合的底层使用的是hash映射机制来存放数据,因此集合中的元素是无序的

Map
Map是一种键值对形式的数据结构

//常规写法
val map = HashMap<String, Int>()
map.put("Apple", 1)
map.put("Banana", 2)

//Kotlin中建议的写法
map["Apple"] = 1
map["Banana"] = 2
map["Orange"] = 3

Kotlin提供了Map初始化方法mapOf()和mutableMapOf()

val map = mapOf("Apple" to 1, "Banana" to 2, "Orange" to 3)
//for-in 循环有所不一样
for ((fruit, number) in map) {
    println("fruit is " + fruit + " number is " + number)
}

4.2 集合的函数式API

先看一段代码

val list = listOf("apple", "orange", "banana")
val maxLengthFruit = list.maxBy { it.length }
println("maxLength fruit is: " + maxLengthFruit)
//好吧,看不懂......

Lambda就是一小段可以作为参数传递的代码
正常情况下,向某个函数传参数时只能传入变量,借助Lambda允许传入一小段代码

Lambda语法结构

{ 参数名1: 参数类型, 参数名2: 参数类型 -> 函数体 }
  • 最外层是一对大括号,如果有参数传入到lambda表达式中的话,还需要声明参数列表.
  • 参数列表的结尾使用一个"->"符号,表示参数列表的结束以及函数体的开始
  • 函数体通常不建议太长,但是Kotlin中并没有规定不太长是多长
  • 函数体最后一行代码会默认作为Lambda表达式的返回值

再来看一段代码

val list = listOf("apple", "orange", "banana")
val lambda = { fruit: String -> fruit.length }
val maxLengthFruit = list.maxBy (lambda)

接下来进行一系列眼花缭乱的操作:

首先,不需要特别定义一个lambda变量

val maxLengthFruit = list.maxBy ( { fruit: String -> fruit.length } )

然后,Kotlin规定,当Lambda参数是函数的最后一个参数时,可以将Lambda表达式移到函数括号的外面

val maxLengthFruit = list.maxBy () { fruit: String -> fruit.length }

接下来,如果Lambda参数时函数的唯一一个参数的话,还可以将函数的括号省略掉

val maxLengthFruit = list.maxBy { fruit: String -> fruit.length }

最后,当Lambda表达式的参数列表只有一个参数时,也不必声明参数名称,直接使用it来代替

val maxLengthFruit = list.maxBy { it.length }
posted @ 2020-06-09 14:33  张小凡I4CU  阅读(233)  评论(0编辑  收藏  举报