回顾 kotlin 之 kotlin 基础

[TOC]

kotlin 基础

java 中有 main()方法作为程序的入口,那么在 kotlin 里边也是类似的,也是提供了一个入口函数,如下:

fun main(args: Array<String>) {
    println("Hello World")
}

在 kotlin 定义一个函数(或者称之为方法)是以fun开头的,这有点类似于 JS 里边的 function 似的.其中的args: Array<String>指的是这个函数的参数,在 kotlin 中,参数类型是放在后边而参数名是在前边的,这个跟 java 中是正好相反的.
println(message)就是 kotlin 中的输出语句,内部实际调用了System.out.println(message).

基本语法

注释

// 这是单行注释
/*
*   这是多行注释
*/
/**
* 这是文档注释
**/

变量

kotlin 中的变量,分为可变变量不可变变量.
可变变量用var修饰,一次赋值,支持多洗修改;不可变变量用val修饰(等价于 java 中用 final 关键字修饰的变量),一次赋值,不可更改.
kotlin 声明变量的时候,类型是在后边声明的.
举例:

var a: String = "a" // 声明一个 String 类型的变量 a
val b: String = "b" // 声明一个 String 类型的常量 b,不可重新赋值

a = "aa" // 没问题
b = "bb" // 会报错
变量的数据类型

kotlin 中的数据类型,分为数值型,字符型,布尔型,数组性,字符串型等

数值类型
Byte,Float,Double,Int,Long,Short
布尔类型
Boolean
字符类型
Char
字符串类型
String
数组类型
常规使用是Array,但是针对某些特殊的比如 Int,Boolean 的数组,提供了特殊的格式IntArray,BooleanArray

举例说明:

    var byte: Byte
    var float: Float = 1.0F
    var double: Double = 2.0
    var int: Int = 3
    var long: Long = 33
    var short: Short = 4
    var boolean: Boolean = false
    var char: Char = 'c'
    var string: String = "string"
    var intArray: IntArray = intArrayOf(1, 2, 3)
    var booleanArray: BooleanArray = booleanArrayOf(false, true)
    var stringArray: Array<String> = arrayOf("a", "b", "c")

运算符

算术运算符,赋值运算符,比较运算符,逻辑运算符.跟 java 中没什么区别

字符串

定义同 java 中的字符串,定义以及普通用法一样一样的...

    val s = "Hello Kotlin" // 定义一个字符串
    println(s)
    println(s[0]) // 根据索引值来获取对应位置上的字符
    for (c in s) { // 对字符串进行遍历
        print("$c,")
    }
    println()
    // 同时,kotlin 标准库中也提供了对应的字符串遍历的方法。
    s.forEach {
        print("$it,")
    }

kotlin 中一些增加的方法.

字符串查找
println(s.first()) // 获取第一个字符
println(s.last()) // 获取最后一个字符
println(s.get(1)) // 获取索引值为 1 的字符
println(s.lastIndexOf("l")) // 获取指定字符最有一次出现的索引值

字符串截取

方法同 java 中的 subString()

字符串替换

同 java 中的 replace()

模板表达式

java 中要使用一个变量,需要用+号拼起来用,如下

String a = "a";
String ab = a + "b";

但是 kotlin 中可以使用$来实现模板化,可以直接在双引号之间引入你所需要的变量.单个引用可以省略掉{}

    val a = "a"
    val b = "${a}b"
    println("b = $b") // b = ab

选择结构语句

if 语句和 when(等同于 java 中的 switch/case) 语句

if 语句

if 语句的使用,跟 java 中一模一样

    // if 语句
    val point = 60
    if (point < 60) {
        println("不及格")
    } else if (60 < point && point < 90) {
        println("良好")
    } else {
        println("优秀")
    }

三元运算符
kotlin 中不存在三元运算符,但是可以使用如下实现:

val result = if (point < 60) "淘汰" else "过关"
when 语句

when 语句其实就是 java 中的 switch/case 语句.

    // when 语句
    val season = 3
    val seasonResult = when (season) {
        1 -> "春季"
        3 -> "春季"
        6 -> "夏季"
        12 -> "冬季"
        else -> "未知季节"
    }

示例代码中,将 when 语句的返回值赋给了一个变量,然后进行输出,可以看到, ->符号前边的就是各种 case,后边的就是需要匹配的内容.
同时也支持多个 case 匹配,比如 1,2,3 都是春季,那么可以采用如下写法:

    val seasonResult = when (season) {
        1, 2, 3 -> "春季"
        4, 5, 6 -> "夏季"
        else -> "其他季节"
    }

循环结构语句

while,do..while 等循环结构都跟 java 中一样,使用方法也是一样的.主要学一下 for 循环.
kotlin 中的 for 循环是这样的.

for(循环对象 in 循环条件) {
    执行语句
}

其中的in其实是 kotlin 中的范围,

普通 for 循环

下边的代码就是循环 4 次,输出 4 次日志.其中的in指的是范围,1..4中的..指的是区间,等价于大于等于 1,小于等于 4,所以最后的实际输出是 4 次.

    // for 循环
    for (i in 1..4) {
        println("string--->$i")
    }
forEach(),forEachIndexed()

kotlin 中还提供了两个增强类型的for 循环,主要针对数组和集合,但是所有对象都可用.
forEach{}: 接收一个闭包参数

    val forArray = arrayOf("a", "b", "c")
    forArray.forEach {
        println("forEach----$it")
    }

forEachIndexed{}: 两个参数,第一个是角标;第二个是元素

    forArray.forEachIndexed { index, it ->
        println("forEachIndexed----index=$index  it=$it")
    }

区间

区间指的是一类数据的集合,比如在数学中的[1,3],[1,3)等.

rangeTo(Int) & ..

rangeTo(Int)函数构成了区间表达,可以用..操作符来简写

    // 区间
    val qujian = 1.rangeTo(3) // 等价于 1 <= qujian <= 3
    for (index in qujian) {
        println("区间的值:$index")
    }

此处可以把rangeTo() 替换成..操作符来实现,效果一致

until 操作符

假如我要实现 1 <= index < 3 ,kotlin 里边怎么写?
在 kotlin 中,有个 until操作符,效果可以实现右边开区间的效果,如下:

    // 输出结果只有 1,2 两个值,因为右边不包含 3
    for (index in 1 until 3) {
        println("until的值:$index")
    }
downTo(Int)

要是想实现逆序遍历区间呢?
kotlin 里边提供了downTo(Int)方便的实现逆序区间.

    // 输出:3,2,1
    for (index in 3.downTo(1)) {
        println("区间的值:$index")
    }
步长 step

前边说的区间,遍历的时候都是步长是 1 的,也就是保证输出是 1,2,3... 假如我要实现输出 1,3,5...呢?
kotlin 里边提供了step关键字,支持设置步长.使用很简单,就是在循环条件之后加上step关键字,然后指定你需要的步长就行了,比如下边是保证了输出奇数...

    // 输出 1,3,5,7,9
    for (index in 1..10 step 2) {
        println("step = $index")
    }

数组

kotlin 中的数组,用 Array 表示,通过泛型来控制数组中的元素类型.

    // 数组
    val array = arrayOf<String>("a", "b", "c")
    // 通过[]直接获取索引值处的元素
    println("索引值为 1 的元素是:${array[1]}")
    println("索引值为 1 的元素是:${array.get(1)}")
    println("数组的长度是:${array.size}")
数组常见操作

遍历
kotlin 中常见的遍历方法有 for 循环遍历和 forEach 遍历,同时都提供了按照索引值遍历的方案.

    // 遍历
    array.forEach {
        println("数组元素:$it")
    }
    array.forEachIndexed { index, content ->
        println("数组元素:index=$index  content=$content")
    }
    for (content in array) {
        println("数组元素(for 循环):$content")
    }
    for ((index, content) in array.withIndex()) {
        println("数组元素(withIndex):index=$index content=$content")
    }

修改数组的值
kotlin 的数组中提供了set(index, value)方法用来修改指定索引值上的值,同时可以简写为[]

    array.set(1, "bb")
    array[1] = "bb"

获取元素的索引值
通过indexOf(value)可以获得指定元素在数组中的索引值.

    println("值为 b 的索引值是:${array.indexOf("b")}")

变量类型转换

kotlin 中的类型转换,包括智能类型转换和强制类型转换.

类型检查

kotlin 中可以采用is或者!is来判断是否是某种类型的.

    // 类型判断
    val typeBoolean: Boolean = false
    println("typeBoolean 的类型是:${typeBoolean is Boolean}")
智能类型转换

在 kotlin 中,经过is类型判断之后,kotlin 会智能的转换成当前判断的类型

强制类型转换

在 kotlin 中可以采用as关键字实现强制类型转换,同时可以使用as?进行安全的类型转换.

    val aStr = "aaaa"
    val bString = aStr as String
    println("bString 的类型是:${bString.javaClass}") // class java.lang.String

接下来我尝试将一个 Int 类型的转换成 String 类型的试试

    val aInt = 1
    val bInt = aInt as String
    println(bInt)

此时会报错:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at com.yanftch.review.kotlinbasic.KtKt.main(Kt.kt:137)
这就是类转换异常的报错,那么在 kotlin 中该怎么避免你呢? 这就是下边说的as?关键字了,他可以在上述情况下避免抛出异常.
所以上边的代码,如果采用 as? 的话,最后会正常输出,但是输出的值是 null

    val aInt = 1
    val bInt = aInt as? String
    println(bInt) // 输出 null

空值处理

空指针异常是最常见的开发异常,那么 kotlin 中是怎么处理空指针异常呢?

可空类型变量 ?

在 kotlin 可以通过?指定一个变量是可空的变量,可空变量可以赋值为 null,

var name: String // 不可空变量
var age: Int? // 可空变量

上边的代码中,制定了 name 为不可空变量,那么如果给赋值 null 就会报错,相反,age 变量指定了为可空变量,那么就可以赋值为 null.

安全调用符 ?.

当一个变量为可空的时候,我们在使用的时候,需要对他做空判断之后再用,kotlin 中可以直接使用?.操作符进行可空类型的变量的调用,也不会出现任何问题.

val name: String? = null
print(name?.toString())
Elvis 操作符 ?:

采用 ?. 调用的时候,如果调用者是为空的,那么返回地同样也是空, 如果我不想要 null 而是想要一个默认值呢?那么很简单,可以采用?:操作符, 他的用处是:调用者如果不为空,那么就返回该有的值(也就是?:前边的值);调用者为空,那么就返回设置好的默认值(也就是?:后边的值)

    val name: String? = null
    val nameResult = name ?: "default"
    println("nameResult 的值是: $nameResult")

name 为空的时候,返回的值就是 "default",不为空,就返回 name 的实际值.

函数/方法

kotlin 中的函数,也就是方法,用处跟java 中一样,但是增加了一些自己的特性.

函数的定义

kotlin 中的函数,需要通过关键字fun来定义. 通过一个简单的函数来学习

    fun method(a: Int, b: Int): Int {
        val sum = a + b
        return sum
    }
  • fun: 函数的命名关键字
  • method: 函数的名字
  • (a: Int, b: Int): 表示的是两个参数,其中分号前边是参数名称,后边是参数类型,多个参数之间用逗号分开
  • Int: 大括号前边的这个 Int 表示的是当前函数的返回值类型.
  • val sum = a + b: 函数体
  • return sum: 表示的是函数的返回值.

如果一个函数不返回任何类型,那么实际是返回的Unit类似 java 中的void.可省略不写.

函数的类型

函数整体分为:有(无)参函数; 有(无)返回值函数

kotlin 中,如果函数体只有一行,那么可以省略返回值类型以及大括号,用一行代码来实现,如下:

fun getAge() = 18
函数的参数

函数的参数,主要将具名参数和默认参数.

具名参数
就是指的在使用的时候,显示的表明参数的名称,这样可以忽略参数的顺序

    // 具名函数
    fun method2(name: String, age: Int) {
        println("name=$name, age=$age")
    }
    // 调用
    method2(age = 18, name = "tom")

默认参数
java 中可以通过方法重载,实现同名函数,不同参数,在 kotlin 中可以使用一个函数来实现类似重载的作用.
就是在函数的定义的时候,给某些指定的参数声明默认值.比如上边的函数,可以给 age 指定默认为 20,那么就算是后续调用函数的时候,不设置 age 的值,他的输出也是 20

    fun method2(name: String, age: Int = 20) {
        println("name=$name, age=$age")
    }
    // 调用
    method2(name = "tom") // 输出:name=tom, age=20

面向对象

会 java 的,面向对象还需要说吗?~~~

类与对象

类定义

声明一个类,也是使用class关键字

class User1 constructor(name: String) {
    private var mName: String? = null
    private var mAge: Int = 0
    fun user1Method() {
        println("name=$mName,  age=$mAge")
    }
}

mName, mAge: 类属性或者类成员变量
user1Method: 类方法

对象创建

在 java 中需要 通过 new关键字来实例化一个对象,但是在 kotlin 可以省略掉他.

val user1 = User1()

然后可以对应的调用类的成员变量和函数

user1.mAge
user1.user1Method()

构造函数

构造函数可以对类中的一些变量进行初始化操作赋值. kotlin 可以直接在类定义的时候指定构造函数,称之为主构造,然后可以在内部创建次要构造.
主构造:
constructor修饰,作用于类头和类名之间,如果没有参数的话可以省略.

class User1 constructor(name: String) {}

如上就是通过主构造函数给当前类传递了一个参数.
name 参数的使用的话,就是可以直接在 kotlin 中的init{}代码块中进行处理.

class User1 constructor(name: String) {
    private var mName: String? = null

    init {
        this.mName = name
    }
}

次要构造
一个类可以有多个次要构造函数.
也需要用那个关键字修饰

    // 定义次构造函数,传递两个参数,并调用主构造函数
    constructor(name: String, age: Int) : this(name) {
        this.mAge = age
    }

this 关键字
作用同 java 中

类继承

让子类拥有父类的特性.java 中通过extends关键字实现子类继承父类,kotlin 中通过:来实现.
kotlin 中所有的类默认是final 的,不能被继承,所以你需要对你要继承的类用 open 关键字修饰

class User2 constructor(name: String) : User1(name) {

}
// User1 只有一个构造函数,传参 name,那么子类继承时需要传.
  • 单继承:一个类只能有一个直接父类
  • 支持多层继承
函数重写

方法的重写,存在于子类和父类之间,同 java 中,需要override修饰.

Any 和 Object

在 java 中,所有类的根本父类是 Object, 但是 Kotlin 中的根本父类是Any, Any 在运行时,会自动映射成 Object 对象.

常见类

嵌套类

kotlin 中,一个类内部再声明一个类, 成为嵌套类,嵌套类默认不持有外部的引用,因此不能访问到外部的变量或者函数,如果希望可以引用,需要将内部的类,用inner关键字修饰.
如下代码中, 在嵌套类里边会报错,提示找不到那两个参数.

class Outer {
    private var mName: String? = null
    private var mAge: Int = 0

    class Inner {
        init {
            println("name=$mName,  age=$mAge")
        }
    }
}

通过字节码反编成 java 文件,发现,不用inner修饰的内部的类,其实等同于 java 中的静态内部类.加了修饰之后,就是普通的内部类.

总结

数据类

在java 中,定义一个类,要想外部访问,需要提供 set/get 方法,但是在 kotlin 中,只需要在类声明的时候在class 前边加上data关键字修饰就行了, 内部自动提供 set/get 方法.

data class DataClassModel(var name: String, var age: Int)
// 其他地方调用
println("${dataClassModel.age}, ${dataClassModel.name}")

DataClassModel 实例化之后,可以直接通过.来获取对应的属性.

单例模式

集合

lambda 编程

泛型

Gradle

协程

DSL

kotlin 与 java 合作

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容