Kotlin 是一门现代但已成熟的编程语言,旨在让开发人员更幸福快乐。 它简洁、安全、可与 Java 及其他语言互操作,并提供了多种方式在多个平台间复用代码,以实现高效编程。Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,被称之为 Android 世界的Swift,由 JetBrains 设计开发并开源。
Kotlin 可以编译成Java字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。
在Google I/O 2017中,Google 宣布 Kotlin 成为 Android 官方开发语言。

1.内置数据类型

1.基本类型

String 字符串

Char 字符

Boolean 布尔

Int 整型

Double 浮点数

List 集合

Set 无重复的元素集合

Map 键值对的集合

1
2
3
fun main{
var name:string = "Array"
}

val ===> 不可改变相当于js的readonly

1
2
3
fun main{
var name:string = "Array"
}

const val====>编译时常量 修饰符const不能修饰局部

只能在函数之外定义

1
2
3
4
const val PI = 3.1415
fun main{
var name:string = "Array"
}

2.数字类型

Byte

Short 短整型

Int 整型

Long 长整型 可以用_表示,计数 100_000_000

1
2
var n1:Long =10L
var n2:Long =100_000_000

UByte

UShort

UInt

ULong

无符号 在后面加上u或U和长整型类似

1
2
3
var n3:UInt = 123u
var n4:UInt = 123U
var n5:ULong = 123UL

Float

Double

默认为Double类型,如果要使用float要加上f或者F

1
2
3
var m1:Float = 1.12F
var m2:Double = 1.12
var m3:Float = 1.12f

3.Boolean类型

0,false,null为假,其他为真

&& || !

4.字符类型

使用.code获取ascII码

\u转义成字符(unicode编码)

1
2
3
4
5
val c1:Char = 'a'
println(c1.code)

val c2:Char ='\u2C77'
println(c2)

5.字符串

用三引号包括字符串=>原始字符串

.trimIndent()去掉空格

$变量名 格式化字符串

1
2
3
4
5
6
7
val s2:String = """
aha
sjs
dld
kjl
""".trimIndent()
println(s2)
1
2
3
val s3:String = "$PI1 圆"
println(s3)
val s3:String = "${PI1} 圆" //可以用{}此时后面不用再加空格,{}里面也可以写表达式

6.运算符

与 and 或or 异或xor

shl 左移位 shr 右移位 ushr无符号右移位

2.条件语句

1.when 类似 switch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
when (c) {
1 -> {
println("1")
}

2 -> {
println("2")
}

3 -> {
println("3")
}

else -> {
println("0")
}
}

2.for循环

..区间运算符20..100相当于 20 <= a <= 100

1
2
3
4
5
6
7
8
val Range1 = 5..10
val Range2 = 5..10
for (i in Range1 step 2){//一次+2
println(i)
}
for (i in 10 DownTo 1){//从10到1
println(i)
}

3.函数

函数可以嵌套使用即函数内部声明函数,在函数内部声明的函数只能在函数内部调用,并且可以使用嵌套该函数的函数体内的变量

1
2
3
4
5
6
7
8
9
10
11
fun main(){
outer()
}

fun outer(){
val value = 10
fun inner(){
println(value)
}
inner()
}

message:String指定形参类型

():unit指定返回值类型 unit相当于void即无返回值(可以省略不写)

1
2
3
fun test(message:String):Unit{
println(message)
}

设置默认值

1
2
3
4
5
fun test1(a:Int=3,b:Int=6):Int{
return a+b
}
//如果要指定第二个参数
test1(b=9)

简洁写法 返回值为a+b

1
fun test2(a:Int,b:Int) = a+b

引用函数

1
2
3
4
5
6
7
8
 fun main(){
val test2 = ::test1
test2()
}

fun test1(){
println("hahha")
}

4.变量作用域

1.get set

1
2
3
4
5
6
7
8
9
10
var v:Int = 10
get() = field * 100
set(value) {
println("赋值")
field = 12
}

fun main(){
println(v)
}

5.常用库函数

var value1 = readln()

相当于Java的Scanner

1
2
3
4
5
6
7
8
9
10
//n次方
println(2.0.pow(4))
//绝对值
println(abs(value2))
//最小值
println(min(10,20))
//最大值
println(max(10,20))
//求根
println(sqrt(9.0))
1
2
3
4
5
6
7
8
9
10
11
12
//e
println(Math.E)
//pai
println(Math.PI)

println(sin(0.5*Math.PI))
println(cos(0.5*Math.PI))
println(tan(Math.PI))

println(asin(1.0));
println(acos(1.0));
println(atan(1.0));

5.函数类型变量

1.()->

1.()括号里为参数类型 ->后为返回值类型

1
2
3
4
5
6
7
8
9
10
11
12
fun main(){
val fun1:(Int)->String = outer("Hello")
val name = fun1(10)
println(name)
}

fun outer(name:String):(Int)->String{
//匿名函数
return fun(number:Int):String{
return number.toString()+"个"+name
}
}

2.可以嵌套使用

1
2
3
fun fu1(n1:Int,n2:Int):((String)->String,String) -> String{

}

2.lamda表达式

1
2
3
4
5
//it代指第一个参数
val func1:(String)->Int = {
println(it)
10 //返回的值s
}
1
2
3
4
5
6
var func:(String,String)->Int = { a,b ->
println(a)
println(b)
10
}
println(func("1","2"))

尾随lamda

1
2
3
4
5
6
7
8
9
10
fun main(){
test{
println(it)
10
}
}

fun test(func:(String)->Int){
println(func("Hello"))
}

小实验

1
2
3
4
5
6
7
8
9
10
11
12
val v1 = fu1(10,20)
val f1 = v1("Hello"){
"1"
}
println(f1)

fun fu1(n1:Int,n2:Int):(String,(String)->String) -> String{
println(n1+n2)
return fun(s2:String, fun2:(String)->String):String{
return fun2("1234")+s2
}
}

如果函数调用的是尾随的lamda则标签名字就是函数的名字

1
2
3
4
val fun2:(Int) -> Int = mytest@{
if (it >10 ) return@mytest 10
20
}

3.内联函数

1.声明内联函数

编译之后将函数原封不动加入到调用的位置

1
2
3
inline fun mytest() = { 
println("1")
}

高阶函数使用lamda

内联高级函数的lamda参数可以直接写return不指定标签

1
2
3
4
5
6
7
8
9
10
11
fun main(){
mytest {
return //内联高级函数的lamda参数可以直接写return不指定标签
}
println("Hi")
}

inline fun mytest(func: (String) -> Int):Unit{
println("1")
func("2")
}

在不需要内联的函数形参上添加noinline关键字,可以防止函数调用内联

标签可以指定为外部的函数名称

6.类和对象

1.类的创建

var 可改

val 不可改

1
2
3
class Student constructor(var name:String,val age:Int){

}

如果在类中定义,要赋值

1
2
3
4
class Student {
var name:String = "Jack"
var age:Int = 18
}
1
2
3
4
class Student(name:String,age:Int) {
var name:String = name
var age:Int = age
}

懒加载,在使用之前必须初始化

1
2
3
4
class Teacher{
lateinit var name: String
lateinit var age:Integer
}

2.对象的创建

1
2
3
4
5
6
val s1 = Student("Jerry",44);
println(s1.age)
println(s1.name)

s1.name = "Tom"
println(s1.name)

constructor

当类有主构造函数是,其他次要构造函数都要调用主构造函数

主构造函数可以省略constructor不写

1
2
3
4
5
                //主构造函数
class Student1(var name:String,var age:Int){
//次要构造函数
constructor(name:String):this(name,90)
}
1
2
3
class Student1{
constructor(name:String)
}

3.对象的初始化

在创建对象时会执行init里的代码

可以写多个init 相当于主构造函数的函数体

1
2
3
4
5
class Teacher1(var name:String,var age:Int){
init {
println("创建成功")
}
}

4.基本数据类型常用方法

1
2
3
4
5
6
7
8
9
10
11
val v1:String = "10"
println(v1.toInt())
val v2:String = "samll"
println(v2.uppercase())
val v3:String = "BIG"
println(v3.lowercase())
val v4:String = "how are you"
println(v4.replace('o','m'))

//获取长度(字符串)
println(v4.length)

5.运算符重载

重载二元运算符 +

1
2
3
4
5
class Student constructor(var name:String,var age:Int){
operator fun plus(another:Student):Student{
return Student(this.name+another.name,another.age+this.age)
}
}

重载一元运算符 !

1
2
3
operator fun not():Student{
return Student(this.name.reversed(),this.age)
}

+a a.unaryPlus()

-a a.unaryMinus()

!a a.not()

a– a.dec()

a++ a.inc()

1
2
3
4
5
6
7
operator fun inc():Student{
return Student(name,age++)
}

operator fun dec():Student{
return Student("name",age++)
}

a+=b a.plusAssign(b)

a-=b a.minusAssign(b)

a*=b a.timesAssign(b)

a/=b a.divAssign(b)

a%= b a.remAssign(b)

同时定义+和+=可能会产生歧义

a>b a.compareTo(b) >0

a<b a.compareTo(b) <=0

a>=b a.compareTo(b) >0

a<=b a.compareTo(b) <=0

() invoke

6.中缀函数

println(10 shl 2) 左移位

调用可以省略点和括号

要求:

1.必须是成员函数

2.只能有一个参数

3,参数不能有默认值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Student constructor(var name:String,var age:Int){
operator fun plus(another:Student):Student{
return Student(this.name+another.name,another.age+this.age)
}

operator fun not():Student{
return Student(this.name.reversed(),this.age)
}

operator fun inc():Student{
return Student(name,age++)
}

operator fun dec():Student{
return Student("name",age++)
}

infix fun test(string:String):String{
return name+string
}
}


package demo2

fun main(){
val stu = Student("zs",11)
println(stu test "hahaha")
//也可以当成普通函数调用
println(stu.test("hahaha"))
}

7.空值和空类型

当我们直接给一个变量赋值空null是kotlin在编译阶段就会报错

1
// val ss:String = null --->  XXXX

加上?:表明这是一个可空的类型

1
val ss:String ?= null

加上!!强制调用

1
ss!!.getdata()

安全访问方法

1
ss?.getdata()
1
2
3
val s:Student? = null
val a = s?.getdata() ?: "hahah"
println(a)

?: 类似与三元运算符 ,当对象为空是会执行?:右边的函数

8.解构

component1即为第一个解构的参数

解构()里的变量名可随意取

1
2
3
4
5
6
7
8
9
10
11
12
13
class Car(var name:String,var price:Int) {
operator fun component1() = name
operator fun component2() = price
}

fun main(){
val car:Car = Car("ll",1000)
val (a,b) = car
println(a)
println(b)
//如果不需要第一个解构的值
val (_,b) = car
}

应用-》在lamda表达式中使用

1
2
3
4
val func1:(Car)->String = { (a,b) ->
a+b.toString()
}
println(func1(car))

7.类与继承

1.权限声明

public

private

protected

internal 只能在当前项目内访问,当别人引用我们的项目时,不能使用

2.类的继承

声明继承

被继承的类要要声明open

1
2
3
4
5
6
7
8
public open class Car(internal var name:String, public var price:Int) {
operator fun component1() = name
operator fun component2() = price
}

public class SuperCar:Car("1",1000){

}
1
2
3
4
5
6
7
8
public open class Car(internal var name:String, public var price:Int) {
operator fun component1() = name
operator fun component2() = price
}

public class SportCar(name:String,price: Int):Car("1",1000){

}

当子类未声明主构造函数

1
2
3
4
5
6
7
8
public open class Car(internal var name:String, public var price:Int) {
operator fun component1() = name
operator fun component2() = price
}

public class SportCar:Car{
constructor(name:String,price: Int):super("1",1000)
}

3.方法的重写(覆盖)

可以通过super关键字调用父类的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
public open class Car(internal var name:String, public var price:Int) {
operator fun component1() = name
operator fun component2() = price
open fun run(data:String){
println(data+"1")
}
}

public class SuperCar:Car("1",1000){
override fun run(data: String) {
super.run(data)
}
}

重写成员变量

1
2
3
4
5
6
7
public open class Car() {
open var name:String = "zs"
}

public class sportcar: Car(){
override var name: String = "ls"
}

4.顶层Any类

相当于java的Object

=== 判断是否是同一个引用对象

5.抽象类

1
2
3
4
5
6
7
8
9
10
abstract class annimal{
abstract var name:String
abstract fun say()
}

class cat(override var name: String) :annimal(){
override fun say() {
println("miao")
}
}
1
2
3
4
5
6
7
8
9
10
11
abstract class annimal{
abstract var name:String
abstract fun say()
}

class cat :annimal(){
override var name:String = "cat"
override fun say() {
println("miao")
}
}

6.接口

接口的所有成员变量和类方法都是抽象的,因此可以省略abstract不写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
interface A{
val name:String
fun run1():String
}

interface B{
val age:Int
fun run2():String
}

class stu() :A,B{
override val age: Int = 16
override val name: String ="NAME"
override fun run1(): String {
return "1"
}

override fun run2(): String {
return "2"
}
}

接口也可以实现默认方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
interface A{
val name:String
fun run1():String
}

interface B{
val age:Int
fun run2():String = "AGE"
}

class stu() :A,B{
override val age: Int = 16
override val name: String ="NAME"
override fun run1(): String {
return "1"
}

override fun run2(): String {
return "2"
}
}

如果继承的两个接口有重复函数可以使用<>消除歧义

1
2
3
4
5
6
7
8
9
10
11
12
interface A{
fun run():String = "NAME"
}

interface B{
fun run():String = "AGE"
}

class stu() :A,B{
override fun run(): String = super<A>.run();
override fun run(): String = super<B>.run();
}

7.类的扩展

1
2
3
4
5
6
7
8
9
10
11
class animal{
fun test(){
println("HAHAHA")
}
}

fun animal.test() = println("HELLO")

fun main(){
animal().test()
}

当有重复函数是扩展会失效

添加属性,此时field无法使用

类的扩展会受到访问权限的影响

1
2
3
4
5
var animal.NAME: String
get() = ""
set(value){
println("SET")
}

在扩展的函数中可以直接使用类的成员变量,可以不使用this关键字

1
2
3
4
5
6
class animal{
val name:String = "JKL"
}
fun animal.test() = {
println(name)
}

指定调用的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A{
fun hello(){
println("Hello")
}
}

class B(private val a:A){
fun A.test(){
hello()
this.hello()
this@B.hello()
}

fun hello(){
println("HELLO")
}
}

将一个扩展函数作为参数传递到一个函数类型变量,在具体操作前要增加类型名称

1
2
3
4
5
6
7
fun main(){
val func:String.() -> Int = {
this.length
}
println("hahahahhaha".func())
println(func("hello"))
}

8.范型

1.范型

可以直接接收数值,自动转换类型

1
2
3
4
5
6
7
class Score<T>(var name:T){

}

fun main(){
val stu = Score("123")
}

2.官方高阶扩展函数

apply 传入一个lambda表达式,也就是我们要如何操作这个对象

let 执行一个lamda表达式并将得到的结果作为返回值

also 与apply类似

run 与let类似

1
2
3
4
fun main(){
val a:Any = Any()
a.apply { }
}

3.协变和逆变

1
2
3
4
5
6
class Num<T>(var name:T)

fun main(){
val v1:Num<Int> = Num<Int>(1)
val v2:Num<Number> = v1 //报错
}

虽然Number是Int的父类但是缺类型不匹配

协变 父类接收子类

逆变 子类接收父类

抗变 类型不相关Test<Int>与Test<Number>无关

使用out开启协变,使用in开启逆变

1
2
3
4
5
6
7
//协变
class Num<T>(var name:T)

fun main(){
val v1:Num<Int> = Num<Int>(1)
val v2:Num<out Number> = v1
}
1
2
3
4
5
6
7
//逆变
class Num<T>(var name:T)

fun main(){
val v1:Num<Any> = Num<Any>(1)
val v2:Num<in Number> = v1
}

可以使用*来代指任意类型

4.范型的界限

限制范型的类型

1
2
3
4
5
6
7
//限制上界为Number
class Num<T : Number>(var name:T)

fun main(){
val v1:Num<Int> = Num<Int>(1)
val v2:Num<out Number> = v1
}
1
2
3
4
class Num<T>(var name:T)
where T:C,T:D
open class C
open class D

也可以直接在类或接口的参数中声明

1
2
3
interface Test<out T>{
fun test():T
}

5.类型擦除

内联函数的类型擦除与普通函数的

reified通过该关键字具化类型

1
2
3
4
5
6
7
8
inline fun <reified T> test(value:Any):Boolean{
return value is T
}

fun main(){
val result = test<String>("1")
println(result)
}

9.数组

1.定义和遍历数组

1
2
3
4
5
6
fun main(){
val array:Array<Int> = arrayOf(1,2,3,4,6,5)
for (element in array){
println(element)
}
}

获取长度 array.size

数组在创建完成后数组容量和元素类型是固定不变的后续无法修改

1
2
3
4
5
6
7
8
9
fun main(){
val array:Array<Int> = arrayOf(1,2,3,4,6,5)
//遍历下标和元素
for ((index,element) in array.withIndex()){
println(array[index])
println(index)
println(element)
}
}

数组的创建和使用

1
array.forEach { println(it) }
1
2
//第一个参数为间隔符,第二个参数为开始字符串,第三个为结束字符串
println(array.joinToString(",","[","]"))
1
2
//创造一个长度为5,值都为123的字符串数组
val array:Array<String> = Array(5){"1234"}

2.数组的操作

==号判断内容是否相同

1
2
3
val array1:Array<String> = Array(5){"1234"}
val array2:Array<String> = Array(5){"1234"}
println(array1.contentEquals(array2)) //=>true

拷贝数组

可以指定参数,为拷贝的数量如果数量大于数组大小会用空填充

1
2
3
4
//执行拷贝
var array3:Array<String> = array2.copyOf()
//指定拷贝范围
var array4:Array<String> = array2.copyOfRange(2,3)

分割数组

1
var array5:Array<String> = array2.sliceArray(1..3)

数组可以用加号进行合并

判断指定元素在不在数组

1
2
array2.contains("1234")
"1234" in array2

快速查找元素在哪一位置

1
array2.indexOf("1234")

reversedarray反转数组

sort排序 sortDesc倒排序

可以重写一个类的compareTo方法指定排序规则

1
2
3
4
5
class B():Comparable<B>{
override fun compareTo(other: B): Int {
return B.age - A.age
}
}

vararg 可以接收任意个同类型的参数

3.基本数组类型

1
2
3
4
5
6
7
8
9
Kotlin			Java
ByteArray byte[]
CharArray char[]
ShortArray short[]
IntArray int[]
LongArray long[]
DoubleArray double[]
FloatArray float[]
BooleanArray boolean[]

4.List

可变的列表,可以插入和删除

1
2
3
4
5
6
7
8
fun main(){
val list:MutableList<String> = mutableListOf("1","2","3");
list.add("4")
list.add(1,"5")
list.remove("1")
list.removeAt(1)
println(list)
}

不可变的列表,无法插入删除

1
val list1:List<Int> = listOf(1,2,3)

可以用{}进行初始化赋值

使用for in 进行遍历

1
2
3
4
val list2:List<Int> = List<Int>(3){10}
for (ele in list2){
println(ele)
}

5.Set

没有重复元素,可用于去重

不能在指定位置插入

1
2
3
var set:MutableSet<Int> = mutableSetOf(1,2,3)
//简单的获取元素
println(set.elementAt(0))

集合的运算

1
2
3
4
5
6
7
8
//并集
println(set1 union set2)
println(set1 + set2)
//交集
println(set1 intersect set2)
//差集
println(set1 - set2)
println(set1 subtract set2)

不同类型的set

1
2
3
4
val set1:SortedSet<Int> = sortedSetOf(9,5,3,19) //自动排序
println(set1)
val set2:HashSet<Int> = hashSetOf(1,2,3) // 无序且不重复
println(set2)

6.Map

Pair

1
val pair:Pair<Int,String> = 10001 to "zs"

创建Map

map[键]获取值

1
2
3
4
val map:MutableMap<Int,String> = mutableMapOf(
1001 to "zs",
1002 to "ls"
)
1
2
3
4
//获取所有的键
println(map.keys)
//获取所有的值
println(map.values)

遍历

for in

for each

1
map.forEach{(k,v) -> println(k.toString()+v) }

可以直接+=添加新键值对

键不能重复,否则数据会被覆盖

1
2
map.put()
map.putAll()

7.迭代器

1
2
3
4
5
val iterator:Iterator<String> = array1.iterator()
println(iterator.next())
println(iterator.next())
println(iterator.next())
println(iterator.next())

遍历数组

1
2
3
4
val iterator:Iterator<String> = array1.iterator()
while(iterator.hasNext()){
println(iterator.next())
}

ListIterator可以实现双向遍历

MutableIterable迭代器 可以在遍历的时候进行删除

8.数组的扩展操作

map 类似于js的map对每一个元素进行操作并且返回一个值

1
2
3
val list:MutableList<String> = mutableListOf("AAA","BB","DDD")
val list2 : MutableList<Int> = list.map { it.length }.toMutableList()
println(list2.joinToString())

遍历map

1
2
3
4
5
6
7
val map:Map<String,Int> = mapOf(
"AAA" to 1,
"BB" to 2,
"CCCC" to 3
)
val map1: Map<Int, Int> = map.mapKeys { it.key.length }
val map2 : Map<String,String> = map.mapValues { it.value.toString() }

zip

unzip

1
2
3
4
val zipmap: List<Pair<String, Int>> = list1.zip(list2)
println(zipmap)
val pair:Pair<List<String>, List<Int>> = zipmap.unzip()
println(pair)

associate将列表映射为一个map集合

1
2
val associates : Map<String,Int> = list1.associate { it to it.length }
println(associates)

扁平化处理多维数组

1
2
3
4
 val array= Array(10, {Array(10){0}})
val list = List(10,{List(10){0} })
//展平
println(array.flatten())

array.flatMap { }在遍历的同时映射

filter过滤操作

1
2
3
list1.filter { it >= 10 }
//过滤不为空的元素
list1.filterNotNull()

10.序列

在使用时才会执行其中的语句

1
2
3
4
5
6
val sequence:Sequence<Int> = generateSequence {
println("构造")
10 //返回值
}

println(sequence.iterator().next())

普通的list,在执行操作时就会调用函数

1
2
3
4
5
6
7
8
9
val list:List<String> = mutableListOf("AAA","BB","CCC","dd","EEE","FF")
val result = list.filter {
println("执行1")
it.length > 2
}.map {
println("执行2")
it.lowercase()
}.take(2)
println(result)

进行优化,在调用使用的时候才会执行内部

数据量庞大时推荐使用

1
2
3
4
5
6
7
8
9
val list:List<String> = mutableListOf("AAA","BB","CCC","dd","EEE","FF")
val result = list.asSequence().filter {
println("执行1")
it.length > 2
}.map {
println("执行2")
it.lowercase()
}.take(2)
println(result.joinToString())

11.特殊的类型

1.数据类型

本质是class

1
2
3
data class Data(val name:String,val age:Int){

}

加上data关键字后

自动生成.equals()/.hashCode()

.toString()

.componentN()

.copy()方法

数据类不能是抽象类

主构造函数必须有一个参数

主构造函数变量必须是var或者val

编译器只会根据构造函数生成,因此可以将参数移出主构造函数,equals方法就不会考虑到写在主构造函数之外的变量

2.枚举类型

加上enum关键字

枚举类可以重写内部的抽象函数,当继承了一个接口时,可以在每个枚举类中重写,或者在定义枚举类的类中重写

1
2
3
4
5
6
7
fun main(){
println(Status.ERR.code)
}

enum class Status(var code:String){
ERR("0"),SUCC("1"),COMP("2")
}

可以定义成员函数

1
2
3
4
5
6
7
8
9
10
11
fun main(){   
val status = Status.ERR
println(status.code)
println(status.isERR())
}

enum class Status(var code:String){
ERR("0"),SUCC("1"),COMP("2"); //使用;进行分隔

fun isERR() = this == ERR
}

定义成员变量

1
2
3
4
5
6
7
8
9
fun main(){
println(status.state)
}

enum class Status(var code:String){
ERR("0"),SUCC("1"),COMP("2");

val state:Int = 10
}

使用when

1
2
3
4
5
6
val message:String = when(status){
Status.ERR -> "错误"
Status.SUCC -> "成功"
Status.COMP -> "运行"
}
println(message)

entries获取整个枚举类

1
2
val statuslist = Status.entries
println(statuslist.joinToString())

12.匿名类

1.匿名类

使用object关键字声明匿名类,并且可以用变量接收

1
2
3
4
5
6
7
8
9
fun main(){
val stu = object {
fun test():String{
return "123"
}
}
val message = stu.test()
println(message)
}

如果接口只有一个函数,可以采用简洁写法实现匿名类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fun interface Krunnerable{
fun test()
}

fun main(){
val stu = object {
fun test():String{
return "123"
}
}
val message = stu.test()
println(message)

val runnerable = Krunnerable{
println("1234")
}
}

单例对象

1
2
3
4
5
6
7
8
9
10
11
object Run{ 通过objext关键字
val name:String = "name"
override fun toString(): String {
return super.toString()
}
}

fun main(){
val run = Run //单例对象直接使用类型得到实例化对象
println(run.toString()) //可以直接使用内部的方法
}

2.伴生对象

companion

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Animal(val name:String){
//使用companion 关键字定义半生对象
companion object Cat{
val age:Int = 90
fun test(){
println("test")
}
}
}

fun main() {
//可以直接使用外面的类名访问内部的方法
Animal.test()
}

13.委托模式

使用by关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//定义接口
interface Base{
fun test()
}
//接口实现
class BaseImpl():Base{
override fun test() {
println("test")
}
}
//委托代理
class Work(val base:BaseImpl) : Base by base //实现Base接口,但是让base帮忙重写

fun main() {
//可以直接使用外面的类名访问内部的方法
val work = Work(BaseImpl())
work.test()
}

使用预设代理lazy在调用时赋值

1
2
3
4
5
6
7
class Exe(){
val per:String by lazy { "geren" }
}
fun main() {
val message:String = Exe().per
println(message)
}

属性可以委托属性代理

1
2
3
class Exe1(val name:String){
val per:String by ::name
}

设置观察者

1
2
3
4
5
6
//设置观察者
class Exe2(val name:String){
val per:String by Delegates.observable("初始值"){
prop,new,old -> println("属性值为${prop},新值为${new},旧值为${old}")
}
}

14.密封对象

sealed class A

不能在外部继承使用以及实例化(模块内部)

密封类是可以被继承的,密封类的子类也可以是密封类

15.异常机制

1.异常的定义

1
2
3
4
Exception in thread "main" java.lang.ArithmeticException: / by zero
at demo1.Test5Kt.div(test5.kt:47)
at demo1.Test5Kt.main(test5.kt:42)
at demo1.Test5Kt.main(test5.kt)

自定义Exception

1
2
3
4
5
6
class myException(override val message: String?):Exception(message)

private fun div(x:Int, y:Int):Int{
if (y==0) throw myException("div by zero")
return x / y
}

2.捕获异常

1
2
3
4
5
6
7
val array:MutableList<Int> = mutableListOf(1,2,9)
try{
println(array[3])
}catch (e:IndexOutOfBoundsException){
e.printStackTrace()
}
println("after")

多个catch

1
2
3
4
5
6
7
8
val array:MutableList<Int> = mutableListOf(1,2,9)
try{
println(array[3])
}catch (e:IndexOutOfBoundsException){
e.printStackTrace()
}catch (e:Exception){
e.printStackTrace()
}