Kotlin入门--基础

基础

  • 编译、运行Kotlin 程序
    kotlinc -d destdir srcFile
    kotlin HelloWorldKt

  • Dokka 工具API文档

java -jar dokka-fatjar.jar KDocTest.kt test.kt
java -jar dokka-fatjar.jar KDocTest.kt test.kt -format javadoc
  • 关键字
  1. 硬关键字(fun, for, class, package,return ...)
key 意义 例子
as 用于做类型转换或为import 语句指定别名 x
as ? 类型安全的类型转换运算符。 x
in 在for 循环中使用; in 还可作为双目运算符,检查一个值是否处于区间或集合内;in 也可在when 表达式中使用; in 还可用于修饰泛型参数,表明该泛型参数支持逆变 x
!in 可作为双目运算符m 的反义词:! in 也可在when 表达式中使用 x
typealias 用于定义类型别名。 typealias Ainner =A. Inner
val 声明只读属性或变量 x
  1. 软关键字
    by一一用于将接口或祖先类的实现代理给其他对象。
    catch 一一在异常处理中用于捕捉异常。
    constructor一一用于声明构造器。
    delegate一一用于指定该注解修饰委托属性存储其委托实例的字段。
    dynamic一一主要用于在Kotli n/JavaScript 中引用一个动态类型。
    field 一一用于指定该注解修饰属性的幕后字段。
    file一一用于指定该注解修饰该源文件本身。
    finally 一一异常处理中的finally 块。
    get 一一用于声明属性的getter 方法,或者用于指定该注解修饰属性的getter 方法。
    import一一用于导包。
    init一一用于声明初始化块。
    param 用于指定该注解修饰构造器参数。
    property一一用于指定该注解修饰整个属性(这种目标的注解对Java 不可见,因为Java并没有真正的属性)。
    receiveris 一一用于指定该注解修饰扩展方法或扩展属性的接收者。
    set 一一用于声明属性的se忧er 方法,或者用于指定该注解修饰属性的se忧er 方法。
    setparam 一一用于指定该注解修饰se忧er 方法的参数。
    where一一用于为泛型参数增加限制。

  2. 修饰符关键字
    abstract一一用于修饰抽象类或抽象成员。
    annotation 一一用于修饰一个注解类。
    companion 一一用于声明一个伴生对象。
    const一一用于声明编译时常量。
    crossinline一一用于禁止在传给内联函数的Lambd a 表达式中执行非局部返回。
    data 一一用于声明数据类。
    enum 一一用于声明枚举。
    external 一一用于声明某个方法不由Kotlin 实现(与Java 的native 相似〉。
    final 一一用于禁止被重写。
    infix一一声明该函数能以双目运算符的格式执行。
    inline 一一用于声明内联函数, Lambda 表达式可在内联函数中执行局部返回。
    inner一一用于声明内部类,内部类可以访问外部类的实例。
    internal 一一用于表示被修饰的声明只能在当前模块内可见。
    lateinit 用于修饰一个non-null 属性,用于指定该属性可在构造器以外的地方完成
    初始化。
    noinline 一一用于禁止内联函数中个别Lambda 表达式被内联化。
    open 一一用于修饰类,表示该类可派生子类;或者用于修饰成员,表示该成员可以被重写。
    out 一一用于修饰泛型参数,表明该泛型参数支持协变。
    override 一一用于声明重写父类的成员。
    private -private 访问权限。
    protected -protected 访问权限。
    public-public 访问权限。
    reified一一用于修饰内联函数中的泛型形参,接下来在该函数中就可像使用普通类型
    一样使用该类型参数。
    sealed一一用于声明一个密封类。
    suspend一一用于标识一个函数后Lambda 表达式可作为暂停。
    tailrec一一用于修饰一个函数可作为尾随递归函数使用。
    vararg一一用于修饰形参,表明该参数是个数可变的形参。

1.程序入口点

Kotlin 应用程序的入口点是 main 函数。严格区分大小写

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

2.函数

  • 带有两个 Int 参数、返回 Int 的函数:
fun sum(a: Int, b: Int): Int {
    return a + b
}
  • 将表达式作为函数体、返回值类型自动推断的函数:
fun sum(a: Int, b: Int) = a + b
  • 函数返回无意义的值(Unit 返回类型可以省略):
fun printSum(a: Int, b: Int): Unit {
    println("sum of $a and $b is ${a + b}")
}

等同

fun printSum(a: Int, b: Int){
    println("sum of $a and $b is ${a + b}")
}

3.变量 val和var

var I val 变盘名[:类型] [=初始值]
Byte 、Short、Int 、Long 型(基本类型)变量都不能接受null 值,如果要存储null 值,则应该使用Byte?、Short?、Int?、Long?(引用类型)类型

  • 定义只读局部变量使用关键字 val 定义。只能为其赋值一次。
val a: Int = 1  // 立即赋值
val b = 2   // 自动推断出 `Int` 类型
val c: Int  // 如果没有初始值类型不能省略
c = 3       // 明确赋值
  • 可重新赋值的变量使用 var 关键字:
var x = 5 // 自动推断出 `Int` 类型
x = 1
  • 顶层变量:
val PI = 3.14
var x = 0

fun incrementX() { 
    x += 1 
}

4.字符串模板

// 模板中的简单名称:
val s1 = "a is $a" 

a = 2
// 模板中的任意表达式:
val s2 = "${s1.replace("is", "was")}, but now is $a"

5.条件表达式

fun maxOf1(a: Int, b: Int): Int {
    if (a > b) {
        return a
    } else {
        return b
    }
}
// or
fun maxOf2(a: Int, b: Int) = if (a > b) a else b

=== 未原始类型(地址)比较
==为值比较(较小类型并不是较大类型的子类型,会导致int和long比较不相等,因此较小的类型不能隐式转换为较大的类型,只能显示b.toInt())

  • Kotlin 不支持三目运算符

6. 运算符

  • 每个运算符都有对应的方法,eg: -a 对应a.unaryMinus()
  • 单目前缀运算符 +a
  • 自加和自减运算符 a++ a.inc()
  • 双目算术运算符 a .. b a.rangeTo(b) a%b a.rem(b)
  • in 和! in 运算符
  • 索引访问运算符 a[i] a.get(i)
  • 调用运算符 a() a.invoke()
 fun main(args : Array<Striηg>) {
val s = ” j ava.lang.String”
//使用反射获取String 类的length ()方法
val mtd = Class . forName(s) . getMethod (” length”)
//使用传统方法,使用Method 对象的invoke ()方法
println(mtd.invoke (” java”)) //输出4
//使用调用运算符
println(mtd (” java”)) //输出4
}
  • 广义赋值运算符 a%=b

  • 相等与不等运算符

  • 比较运算符 a > b a.compareTo(b) > 0

  • 位运算符 and(bits)or(bits )

  • 区间运算符

    1. 闭区间运算符a .. b
    2. 半开区间运算符 a until b 不包含b
    3. 反向区间 a down To b :a到b,b<a
    4. 区间步长 num in 7 downTo 1 step 2
  • 运算符重载

data class Data(val x : Int, val y : Int) {
//为Data 类定义一个inc ()方法
operator fun inc() : Data {
return Data(x + 1 , y + 1)
}
//以扩展方法的形式为Data 类定义dee ()方法
operator fun Data.dec(): Data {
return Data(x - 1 , y - 1)
}
fun main(args : Array<String>) {
var d = Data(4 , 10)
println (d++) //先用,再自加,输出Data(x=4 , y=lO)
println(d) //输出自加后的民Data (x=S, y=ll)
var dd = Data(9 , 20)
println(--dd) //先自减, 再用,输出Data (x=8, y=l9)
println(dd) //输出自加后的dd : Data (x=8, y=l9)
}

7. 空值与 null 检测

当某个变量的值可以为 null 的时候,必须在声明处的类型后添加 ? 来标识该引用可为空。可为空时,则必须判断是否为空

fun parseInt(str: String): Int? {
    // ……
}

使用返回可空值的函数:

fun printProduct(arg1: String, arg2: String) {
    val x = parseInt(arg1)
    val y = parseInt(arg2)

    // 直接使用 `x * y` 会导致编译错误,因为它们可能为 null
    if (x != null && y != null) {
        // 在空检测后,x 与 y 会自动转换为非空值(non-nullable)
        println(x * y)
    }
    else {
        println("'$arg1' or '$arg2' is not a number")
    }    
}

8.安全调用 / 强制调用

  • user? . dog?.name
    如果user 不为null ,则返回user 的dog 属性;如果dog 属性值不为
    null ,则继续获取dog 属性值的name 属性值。反过来,如果user 为null ,或user.dog 为null,
    那么该表达式语言都不会导致NPE ,而是整个表达式返回null
fun main(args: Array<Str 工ng > ) {
var b: String? = ” fkit ”
println(b?.length) //输出4
b = null
println(b?.length) //输出null
}
  • Elvis运算
    如果“?:”左边的表达式不为nu ll ,则返回左边表达式的值,否则返回“?:”右边表达式的值。
fun main(args: Array<String>) {
var b: String? = ” fkit ”
//先判断b 不为null ,然后访问b 的length 属性
var lenl =if (b !=null) b.length else -1
println (lenl);
b = null
//使用Elvis 运算符
var len2 = b?.length ?: -1
println(len2);
}
  • 强制调用 !!.
fun main(args : Array<String>) {
var b : String? = ” fkit ”
println b! . length) //输出4
b = null
println b !!. length) //引发空指针异常( NPE)
// 定义一个元素可空的数组
val myArr : Array<String?> = arrayOf (” fkit ”,”fkjava ”, null ,”crazyit ” )
for (item in myArr) {
//当item 不为null 时才调用let 函数
item !! .let { println(it) }
}
}

9.类型检测与自动类型转换

is 运算符检测一个表达式是否某类型的一个实例。 如果一个不可变的局部变量或属性已经判断出为某类型,那么检测后的分支中可以直接当作该类型使用,无需显式转换:

fun getStringLength(obj: Any): Int? {
    if (obj is String) {
        // `obj` 在该条件分支内自动转换成 `String`
        return obj.length
    }

    // 在离开类型检测分支后,`obj` 仍然是 `Any` 类型
    return null
}

或者

fun getStringLength(obj: Any): Int? {
    if (obj !is String) return null

    // `obj` 在这一分支自动转换为 `String`
    return obj.length
}

甚至

fun getStringLength(obj: Any): Int? {
    // `obj` 在 `&&` 右边自动转换成 `String` 类型
    if (obj is String && obj.length > 0) {
      return obj.length
    }

    return null
}

10.循环语句(break,continue,return)

  • for 循环(java 普通for循环已被抛弃,都是for in)
val items = listOf("apple", "banana", "kiwifruit")
for (item in items) {
    println(item)
}
val items = listOf("apple", "banana", "kiwifruit")
for (index in items.indices) {
    println("item at $index is ${items[index]}")
}
for( i in 1 until 5) {
println ( ” i : $ { i } ”)
// i= 20  i是val不能重新赋值
}
  • while 循环
val items = listOf("apple", "banana", "kiwifruit")
var index = 0
while (index < items.size) {
    println("item at $index is ${items[index]}")
    index++
}
  • do-while循环
var count = 1
//执行do while 循环
do {
println(count)
//循环法代语句
count++
//循环条件紧跟while 关键字
} while (count < 10)
println (”循环结束!”)

11. when表达式

fun describe(obj: Any): String =
    when (obj) {
        1          -> "One"
        "Hello"    -> "Greeting"
        is Long    -> "Long"
        !is String -> "Not a string"
        else       -> "Unknown"
    }
  • break ,带标签必须带@, continue也一样
fun main(args : Array<String>) {
  //一个简单的for 循环
  for (i in 0 .. 10 ) {
    println ("值是:$ { i }")
    if (i == 2) {
    / /执行该语句时将结束循环
      break
    }
  }
}

fun main(args: Array<String>) {
  //外层循环, outer 作为标识符
  outer@ for (i in 0 until 5 ) {
                    // 内层循环
                  for (j in 0 until 3 ) {
                    println ("值为:$ { i} , j 的值为: $ { j } ” )
                    if (j == 1) {
                      //跳出outer 标签所标识的循环
                      break@outer
                    }
                }
              }
}

12. 使用区间(range)

  • 使用 in 运算符来检测某个数字是否在指定区间内:
val x = 10
val y = 9
if (x in 1..y+1) {
    println("fits in range")
}
  • 检测某个数字是否在指定区间外:
val list = listOf("a", "b", "c")
val map = mapOf("a" to 1, "b" to 2, "c" to 3)
if (-1 !in 0..list.lastIndex) {
    println("-1 is out of range")
}
if (list.size !in list.indices) {
    println("list size is out of valid list indices range, too")
}
println(map["a"])
map["b"] = 4
for ((k, v) in map) {
    println("$k -> $v")
}
  • 区间迭代:
for (x in 1..5) {
    print(x)
}

或数列迭代:

for (x in 1..10 step 2) {
    print(x)
}
println()
for (x in 9 downTo 0 step 3) {
    print(x)
}
for (i in 1..100) { …… }  // 闭区间:包含 100
for (i in 1 until 100) { …… } // 半开区间:不包含 100
for (x in 2..10 step 2) { …… }
for (x in 10 downTo 1) { …… }
if (x in 1..10) { …… }

13.Collections (array,List,set,map)抛弃了Java 集合体系中的Queue 集合

  • 数组,工具arrayOf()、arrayOfNulls()array为null、emptyArray()
fun main(args: Array<String>) {
//定义一个数组
var arr= array0f(2 , 4, 5, 6)
//判断是否所有元素的平方都大于20
println(arr .all({it *it> 20})) //输出false
//判断是否任一元素的平方大于20
println(arr . any({it*it>20})) //输出true
//根据数组元素来计算<K , V>对,返回所有< K , V>对组成的Map 集合
//下面的算法规则是: K 是数组元素+ 2, v 是数组元素的平方
var resultl = arr.associate({it + 10 to it* it})
println(resultl)
//创建一个可变Map 集合,用于追加根据数组计算出来的key-value 对
var map= mutableMapOf(l to 100 , 2 to 120 , -1 to 130)
//将计算出来的key (元素的平方)、value (元素)对添加到map 集合中
arr .associateByTo(map, {it* it})
println(map)
//计算数组所有元素的总和
println(arr .fold(0, {ace , e ->ace+ e})) //输出17
//定义一个a 数组
var a= array0f(3 , 4 , 5, 6)
//a 数组和a2 数组的长度相等,每个元素依次相等, 将输出true
println (” a 数组和a2 数组是否相等:${ a.contentEquals(a2 )}”)
//通过复制a 数组,生成一个新的b 数组
var b = a.copyOf (6)
println (” a 数组和b 数组是否相等:${ a.contentEquals(b )}”)
//输出b 数组的元素,将输出[ 3 , 4, 5, 6, null , null]
println ( ” b 数组的元素为: ♀{ b . contentToString ()} ” )
//将b 数组的第5 个元素(包括)到第7 个元素(不包括)赋值为l
b . fill(l , 4 , 6)
//输出b 数组的元素, 将输出口, 4 , 5 , 6 , 1 , l]
println ( ” b 数组的元素为:${ b . contentToString ()} ” )
//对b 数组进行排序
b . sort()
//输出b 数组的元素,将输出口, 1 , 3 , 4 , 5 , 6]
println ( ”b 数组的元素为: ${ b . contentToString() } ” )
  • 二维数组(kotlin无二维数组)
var board = Array(BOARD SIZE , {Array(BOARD SIZE , {""})})
for (i in 0 until BOARD SIZE) {
  for (j in 0 until BOARD_SIZE) {
    board [i][j]= "+"
  }
}
  • 对集合进行迭代:
for (item in items) {
    println(item)
}
  • 使用 in 运算符来判断集合内是否包含某实例:
when {
    "orange" in items -> println("juicy")
    "apple" in items -> println("apple is fine too")
}
  • 使用 lambda 表达式来过滤(filter)与映射(map)集合:
val fruits = listOf("banana", "avocado", "apple", "kiwifruit")
fruits
  .filter { it.startsWith("a") }
  .sortedBy { it }
  .map { it.toUpperCase() }
  .forEach { println(it) }
  • Map 集合,工具mapOf(),mutableMapOf(),hashMapOf(),linkedMapOf(),sortedMapOf(),

14.函数(声明函数必须使用fun 关键字)

fun 函数名(形参列表)[:返回值类型]{
//由0条到多条可执行语句组成的函数
}
  • 返回值使用Unit相当于void,也可以不用写Unit
  • 单表达式函数
fun area(x: Double, y: Double): Double = x * y
  • 支持形参默认值
fun say(name: String =”孙悟空”,message: String =”欢迎来到疯狂软件”}{
}
  • 个数可变的形参vararg
fun test(a:Int , vararg books:String) {
}
  • 函数重载
fun test() {
println ( "无参数的test {)函数")
}

fun test(msg:String) {
println (" 重载的test ()函数${ msg }")
}
  • 内联函数
inline fun map (data : Array<Int> , fn : ( Int ) - > Int ) : Array<Int>{
}

15.创建基本类及其实例

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

推荐阅读更多精彩内容