目录
一.基础
1.1程序入口
fun main() {
println("Hello world!")
}
1.2函数定义
函数定义使用关键字 fun,参数格式为:参数 : 类型
fun sum(a: Int, b: Int): Int { // Int 参数,返回值 Int
return a + b
}
无返回值的函数(类似Java中的void),Unit
返回类型可以省略。
fun printSum(a: Int, b: Int): Unit {
println("sum of $a and $b is ${a + b}")
}
1.3定义常量与变量
定义只读局部变量使用关键字 val
定义。只能为其赋值一次。(类似Java中final修饰的变量)
可变变量定义:var 关键字
val a: Int = 1
val b = 1 // 系统自动推断变量类型为Int
val c: Int // 如果不在声明时初始化则必须提供变量类型
c = 1 // 明确赋值
var x = 5 // 系统自动推断变量类型为Int
x += 1 // 变量可修改
1.4字符串模板
$ 表示一个变量名或者变量值
$varName 表示变量值
${varName.fun()} 表示变量的方法返回值:
1.5空值检测
当可能用 null
值时,必须将引用显式标记为可空。可空类型名称以问号(?
)结尾
//类型后面加?表示可为空
var age: String? = "23"
//如果 str 的内容不是数字返回 null:
fun parseInt(str: String): Int? {
// ……
}
1.6使用区间
使用 in
操作符来检测某个数字是否在指定区间内。
for (i in 1..4) print(i) // 输出“1234”
1.7类型检测与自动类型转换
is
或者其否定形式 !is
操作符检测一个表达式是否某类型的一个实例。 如果一个不可变的局部变量或属性已经判断出为某类型,那么检测后的分支中可以直接当作该类型使用,无需显式转换,类似于Java中的instanceof关键字)。
二.函数
2.1.run,let,apply和also
run:
- 调用同一个对象的多个方法 / 属性时,可以省去对象名重复,直接调用方法名 / 属性即可
- 定义一个变量在特定作用域内
- 统一做判空处理
object.run{
// ...
}
// 返回值 = 函数块的最后一行 / return表达式
let:
// 作用1:使用it替代object对象去访问其公有的属性 & 方法
object.let{
it.todo()
}
// 作用2:判断object为null的操作
object?.let{//表示object不为null的条件下,才会去执行let函数体
it.todo()
}
// 注:返回值 = 最后一行 / return的表达式
apply:
- apply函数返回传入的对象的本身
also:
返回值 = 传入的对象的本身
// also函数
var result = mVar.also {
it.function1()
it.function2()
it.function3()
999
}
// 最终结果 = 返回一个mVar对象给变量result
2.2with函数
作用:调用同一个对象的多个方法 / 属性时,可以省去对象名重复,直接调用方法名 / 属性即可
with(object){
// ...
}
// 返回值 = 函数块的最后一行 / return表达式
2.3takeif和takeUnless
takeIf : 接收一个判断条件表达式,如果判断表达式为true则返回 对象本身,false返回 null
takeUnless: 与takeIf相反, 如果判断表达式为true则返回 null,false返回 对象本身
2.4 if
if
是一个表达式:它会返回一个值。 因此就不需要三元运算符(条件 ? 然后 : 否则
),因为普通的 if
就能胜任这个角色。
//sampleStart
fun maxOf(a: Int, b: Int) = if (a > b) a else b
//sampleEnd
fun main() {
println("max of 0 and 42 is ${maxOf(0, 42)}")
}
2.5 for循环
语法如下:for (item in collection) print(item)
fun main() {
//sampleStart
val items = listOf("apple", "banana", "kiwifruit")
for (item in items) {
println(item)
}
//sampleEnd
}
2.6while循环
fun main() {
//sampleStart
val items = listOf("apple", "banana", "kiwifruit")
var index = 0
while (index < items.size) {
println("item at $index is ${items[index]}")
index++
}
//sampleEnd
}
2.7when表达式
when 类似其他语言的 switch 操作符
在 when 中,else 同 switch 的 default。如果其他分支都不满足条件将会求值 else 分支。
//sampleStart
fun describe(obj: Any): String =
when (obj) {
1 -> "One"
"Hello" -> "Greeting"
is Long -> "Long"
!is String -> "Not a string"
else -> "Unknown"
}
//sampleEnd
fun main() {
println(describe(1))
println(describe("Hello"))
println(describe(1000L))
println(describe(2))
println(describe("other"))
}
如果很多分支需要用相同的方式处理,则可以把多个分支条件放在一起,用逗号分隔:
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
2.8返回和跳转
- return。默认从最直接包围它的函数或者匿名函数返回。
- break。终止最直接包围它的循环。
- continue。继续下一次最直接包围它的循环。
fun main(args: Array<String>) {
for (i in 1..10) {
if (i==3) continue // i 为 3 时跳过当前循环,继续下一次循环
println(i)
if (i>5) break // i 为 6 时 跳出循环
}
}
四.集合
4.1list基础使用
尽量使用getOrElse或者getOrNull,避免出现越界
fun main(){
var list : List<String> = listOf("xiaoxie","xiaofei","xiaozhou","xiaozhi")
//打印字符串
println(list[0])
//getOrElse
println(list.getOrElse(4){"越界了"})//返回越界了
//getOrNull
println(list.getOrNull(4))//返回null
}
4.2 不可变集合和可变集合
不可变集合转化成可变集合:使用toMutableList()
可变集合转化成不可变集合:使用toList()
fun main(){
var list= listOf<String>("xiaoxie","xiaofei","xiaozhou","xiaozhi")
//不可变集合转化成可变集合
var mulist1=list.toMutableList()
mulist1.add("xiaozhao")
mulist1.remove("xiaozhi")
//可变集合转化成不可变集合
var mulist2= mutableListOf<String>("xiaoxie","xiaofei","xiaozhou","xiaozhi")
var list2=mulist2.toList()
}
4.3mutator和removeIf
mutator包括+= 和-= 用法
removeIf用法:当{}为true时,则移除对应的元素
fun main(){
val list= mutableListOf<String>("xiaoxie","xiaofei","xiaozhou","xiaozhi")
list += "xiaoxiao"
list -= "xiaozhou"
println(list)//打印出[xiaoxie, xiaofei, xiaozhi, xiaoxiao]
list.removeIf { it.contains("xiaozhi") } //如果等于xiaozhi,则remove掉
println(list)//[xiaoxie, xiaofei, xiaoxiao]
}
4.4集合遍历
三种遍历方式:forEach,forEachIndexed和for
fun main(){
val list= listOf<String>("xiaoxie","xiaofei","xiaozhou","xiaozhi")
//遍历的三种用法
for (i in list){
println("元素:$i")
}
//foreach
list.forEach{
println("元素:$it")
}
//下标和元素
list.forEachIndexed { index, s ->
println("下标是$index,元素是$s")
}
}
4.5set基础使用
fun main(){
val set= setOf<String>("xiaoxie","xiaofei","xiaozhou","xiaozhi")
//获取元素
println(set.elementAt(0))
//尽量使用此种方式,防止数据越界
println(set.elementAtOrElse(4){"越界了"})//打印越界了
//
println(set.elementAtOrNull(4))//打印出null
}
可变的set:
var set1= mutableSetOf<String>("xiaoxie","xiaofei","xiaozhou","xiaozhi")
其他使用同list一样
4.6list和set的转换
fun main(){
val list= mutableListOf<String>("xiaoxie","xiaofei","xiaozhi","xiaozhi")
//list转化成set
val set=list.toSet()
println(set)//[xiaoxie, xiaofei, xiaozhi]
//list转化成set,在转化成list
val list1=list.toSet().toList()
println(list1)//[xiaoxie, xiaofei, xiaozhi]
//快捷函数去重
val list2=list.distinct()
println(list2)//[xiaoxie, xiaofei, xiaozhi]
}
4.7数组
fun main(){
val intArray= intArrayOf(1,2,3,4,5,6)
println(intArray[0])//1
//获取数组的元素
println(intArray.elementAtOrElse(0){-1})//1
println(intArray.elementAtOrElse(6){-1})//-1
//list转数组
val charArray= listOf('A','B','C').toCharArray()
println(charArray)//ABC
}
4.8 map
fun main(){
val map1:Map<String,String> = mapOf("xiaoxie" to ("xiaofei"),"xiaozhou" to ("xiaozhi"))
val map2 = mapOf(Pair("xiaoxie","xiaofei"), Pair("xiaozhou","xiaozhi"))
//获取value值,建议使用
println(map1["xiaoxie"])//xiaofei
//通过key查找,找不到,返回null
println(map1["xiaoxiao"])//null
//getOrDefault方式
println(map2.getOrDefault("xiaoxie","cc"))//xiaofei
println(map2.getOrDefault("xiaoxiao","cc"))//cc
//getOrElse
println(map2.getOrElse("xiaoxie"){"xx"})//xiaofei
println(map2.getOrElse("xiaoxiao"){"xx"})//xx
//getValue,不建议使用
println(map2.getValue("xiaoxie"))//xiaofei
println(map2.getValue("xiaoxiao"))//提示.NoSuchElementException
}
4.9 map的遍历
fun main(){
val map1:Map<String,String> = mapOf("xiaoxie" to ("xiaofei"),"xiaozhou" to ("xiaozhi"))
//第一种方法
map1.forEach{
println("k:${it.key},V:${it.value}")
}
//第二种方法
map1.forEach { key:String,value:String->
println("k:$key,v:$value")
}
//第三种方法
map1.forEach{(key,value)->
println("key:$key,value:$value")
}
//第四种方法
for (entry in map1){
println("key:${entry.key},value:${entry.value}")
}
}
4.10可变的map
fun main() {
val map = mutableMapOf("xiaoxie" to ("xiaofei"), "xiaozhou" to ("xiaozhi"))
//一般操作
map += "xiaoxiao" to "cici"
map["xiaoxi"]="xixi"
map.put("xiaoyu","cc")
println(map)//{xiaoxie=xiaofei, xiaozhou=xiaozhi, xiaoxiao=cici, xiaoxi=xixi, xiaoyu=cc}
//如果map里没有heihei这个key,则添加进去map,且value值是xixixi
val r=map.getOrPut("heihei"){"xixixi"}
println(map)//{xiaoxie=xiaofei, xiaozhou=xiaozhi, xiaoxiao=cici, xiaoxi=xixi, xiaoyu=cc, heihei=xixixi}
//如果map里有xiaoyu这个key,则获取原有的value值
val r1=map.getOrPut("xiaoyu"){"xixixi"}
println(map)//{xiaoxie=xiaofei, xiaozhou=xiaozhi, xiaoxiao=cici, xiaoxi=xixi, xiaoyu=cc, heihei=xixixi}
}
五.类
5.1类和实例
类的属性可以用关键字 var 声明为可变的,否则使用只读关键字 val 声明为不可变。
class Rectangle(var height: Double, var length: Double) {
var perimeter = (height + length) * 2
}
创建实例:val site = Rectangle() // Kotlin 中没有 new 关键字
使用一个属性,只要用名称引用它即可:site.name // 使用 . 号来引用
5.2构造函数(主构造函数和次构造函数)
在 Kotlin 中的一个类可以有一个主构造函数以及一个或多个次构造函数。主构造函数是类头的一部分:它跟在类名与可选的类型参数后。
class Person constructor(firstName: String) { /*……*/ }
如果主构造函数没有任何注解或者可见性修饰符,可以省略这个 constructor
关键字。
主构造器中不能包含任何代码,初始化代码可以放在初始化代码段中,初始化代码段使用 init 关键字作为前缀。
class Person constructor(firstName: String) {
init {
println("FirstName is $firstName")
}
}
类也可以有二级构造函数,需要加前缀 constructor:
class Person {
constructor(parent: Person) {
parent.children.add(this)
}
}
5.3继承
所有类都继承该 Any 类,它是所有类的超类
类之间继承由冒号(:
)声明。默认情况下类都是 final 的;如需让一个类可继承, 请将其标记为 open
open class Shape
class Rectangle(var height: Double, var length: Double): Shape() {
var perimeter = (height + length) * 2
}
5.4抽象类
xxx
5.5嵌套类
class Outer { // 外部类
private val bar: Int = 1
class Nested { // 嵌套类
fun foo() = 2
}
}
fun main(args: Array<String>) {
val demo = Outer.Nested().foo() // 调用格式:外部类.嵌套类.嵌套类方法/属性
println(demo) // == 2
}
5.6内部类
内部类使用 inner 关键字来表示。
内部类会带有一个对外部类的对象的引用,所以内部类可以访问外部类成员属性和成员函数。
class Outer {
private val bar: Int = 1
var v = "成员属性"
/**嵌套内部类**/
inner class Inner {
fun foo() = bar // 访问外部类成员
fun innerTest() {
var o = this@Outer //获取外部类的成员变量
println("内部类可以引用外部类的成员,例如:" + o.v)
}
}
}
fun main(args: Array<String>) {
val demo = Outer().Inner().foo()
println(demo) // 1
val demo2 = Outer().Inner().innerTest()
println(demo2) // 内部类可以引用外部类的成员,例如:成员属性
}
5.7接口
使用 interface 关键字定义接口,允许方法有默认实现
interface MyInterface {
fun bar() // 未实现
fun foo() { //已实现
// 可选的方法体
println("foo")
}
}
实现接口
class Child : MyInterface {
override fun bar() {
// 方法体
}
}
5.8枚举类
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
5.9数据类
数据类 并以 data
标记,类似于java中的POJO
data class User(val name: String, val age: Int)
数据类必须满足以下要求:
- 主构造函数需要至少有一个参数。
- 主构造函数的所有参数需要标记为
val
或var
。 - 数据类不能是抽象、开放、密封或者内部的。
5.10泛型
class Box<T>(t: T) {
var value = t
}
创建这样类的实例只需提供类型参数即可:
val box: Box<Int> = Box<Int>(1)
fun main(args: Array<String>) {
val age = 23
val name = "runoob"
val bool = true
doPrintln(age) // 整型 整型数字为 23
doPrintln(name) // 字符串 字符串转换为大写:RUNOOB
doPrintln(bool) // 布尔型 T 不是整型,也不是字符串
}
fun <T> doPrintln(content: T) {
when (content) {
is Int -> println("整型数字为 $content")
is String -> println("字符串转换为大写:${content.toUpperCase()}")
else -> println("T 不是整型,也不是字符串")
}
}
泛型函数:
fun <T> singletonList(item: T): List<T> {
// ……
}
调用的话,在调用处函数名之后指定类型参数即可:
val l = singletonList<Int>(1)