基础
编译、运行Kotlin 程序
kotlinc -d destdir srcFile
kotlin HelloWorldKtDokka 工具API文档
java -jar dokka-fatjar.jar KDocTest.kt test.kt
java -jar dokka-fatjar.jar KDocTest.kt test.kt -format javadoc
- 关键字
- 硬关键字(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 |
软关键字
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一一用于为泛型参数增加限制。修饰符关键字
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 )
-
区间运算符
- 闭区间运算符a .. b
- 半开区间运算符 a until b 不包含b
- 反向区间 a down To b :a到b,b<a
- 区间步长 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)