修饰符
修饰符 | 说明 |
---|
private | 只能在当前类中访问 |
protected | 只能在当前类和子类中访问 |
public | 任何类都可以访问(默认) |
internal | 只能在当前模块中访问 |
声明变量
Kotlin
使用val
声明不可变变量,使用var
声明可变变量
1 2
| val name: String = "小明" var age: Int = 18
|
类型推导机制:自动推导变量的数据类型,不需要显式指定
1 2
| val name = "小明" var age = 18
|
但是如果延迟赋值,就必须显式指定类型
1 2 3 4 5
| val name: String val age: Int
name = "小明" age = 18
|
逻辑控制
条件语句
if
Kotlin
的if
语法和Java
基本一致
1 2 3 4 5 6 7 8 9 10 11 12 13
| fun getType(any : Any?) : String { if (any is String) { return "String" } else if (any is Number) { return "Number" } else if (any is Char) { return "Char" } else if (any == null) { return "null" } return "Unknown" }
|
Kotlin
的if-else
语句是一个表达式,可以返回值,返回值即每个条件代码块中的最后一行代码
1 2 3 4 5 6 7 8 9 10 11 12 13
| fun getType(any : Any?) : String { return if (any is String) { "String" } else if (any is Number) { "Number" } else if (any is Char) { "Char" } else if (any == null) { "null" } else { "Unknown" } }
|
进一步简化
1 2 3 4 5
| fun getType(any: Any?) = if (any is String) "String" else if (any is Number) "Number" else if (any is Char) "Char" else if (any == null) "null" else "Unknown"
|
when
when
语句可以替代if
、else if
、else
,并且也可以有返回值
1 2 3 4 5 6 7 8 9
| fun getType(any: Any?) : String { return when (any) { is String -> {"String"} is Number -> {"Number"} is Char -> {"Char"} null -> {"null"} else -> {"Unknown"} } }
|
进一步简化
1 2 3 4 5 6 7
| fun getType(any: Any?) = when (any) { is String -> "String" is Number -> "Number" is Char -> "Char" null -> "null" else -> "Unknown" }
|
when
语句还可以用于范围判断
1 2 3 4 5 6 7 8
| fun getSope(num : Number) { when (num) { in 0..10 -> println("0..10") in 11..20 -> println("11..20") in 21..30 -> println("21..30") else -> println("out of range") } }
|
1 2 3 4
| val r1: IntRange = 1..10
val r2: IntRange = 1 until 10
|
for
for
语句主要用于遍历
1 2 3 4 5 6 7 8 9 10 11
| val list = listOf(1, 2, 3, 4, 5) for (i in list) { println(i) }
val map = mapOf("a" to 1, "b" to 2, "c" to 3) for ((key, value) in map) { println("$key -> $value") }
|
while
while
语句可以用于循环
1 2 3 4 5
| var i = 0 while (i < 5) { println(i) i++ }
|
函数
Kotlin
使用fun
声明函数
1 2 3
| fun test() { println("test") }
|
如果未注明返回值类型,会自动推导为Unit
类型,即无返回值
1 2 3
| fun test(): Unit { println("test") }
|
返回值类型放在形参列表后面,使用:
分隔
1 2 3
| fun add(i1: Int, i2: Int): Int { return i1 + i2 }
|
函数只有一个表达式时,可以省略花括号和return
关键字,用一个等号代替
1
| fun add(i1: Int, i2: Int): Int = i1 + i2
|
因为类型推导机制的存在,可以省略返回值类型
1
| fun add(i1: Int, i2: Int) = i1 + i2
|
Kotlin
中函数可以接收另一个函数作为参数
1 2 3 4 5 6 7 8 9 10 11
| fun execute(func : (num1: Int, num2: Int) -> Int) { val result = func(1, 2) println("result = $result") }
val func = fun (num1: Int, num2: Int): Int { return num1 + num2 } execute(func)
|
类
声明类
Kotlin
使用class
声明类
1 2 3 4
| class User { private var name: String = "" private var age: Int = 0 }
|
类中没有属性和方法时,可以省略花括号
Kotlin
中创建对象不需要使用new
关键字
1 2 3 4 5
| val user = User() user.setAge(18) user.setName("xxin")
println(user.toString())
|
构造函数
Kotlin
中构造函数分为主构造函数和次构造函数,主构造函数只能有一个,次构造函数可以有多个
主构造函数
主构造函数写在类名后面,使用constructor
关键字声明,后面括号中的形参也作为类的属性,在类中可以直接调用,使用var
或val
关键字修饰,constructor
关键字也可以省略
1 2
| class User constructor(private var name: String, private var age: Int) { }
|
如果类没有显式声明任何主
构造函数和次
构造函数,会自动生成一个无参的主构造函数,如下三种写法实际上完全一致
1 2 3 4 5
| class User
class User()
class User constructor()
|
主构造函数没有函数体,如果要在主构造函数中写逻辑,可以写在init
结构体中
1 2 3 4 5 6 7 8 9
| class User(private var name: String, private var age: Int) { init { printInfo() } private fun printInfo() { println("name: $name, age: $age") } }
|
主构造函数中的形参可以省略var
或val
关键字,省略之后的形参不再作为类的属性,只能在init
结构体中被调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class User(name: String, age: Int) { private var name: String private var age: Int
init { this.name = name this.age = age printInfo() }
private fun printInfo() { println("name: $name, age: $age") } }
|
次构造函数
Kotlin
中可以有多个次构造函数,而无主构造函数,使用constructor
关键字声明次构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class User { private var name: String = "" private var age: Int = 0
constructor(name: String) : this(name, 18) { println("一个参数的构造函数") }
constructor(name: String, age: Int) { println("两个参数的构造函数") this.name = name this.age = age } }
|
当一个类既有主构造函数又有次构造函数时,所有次构造函数必须直接或间接的调用主构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| open class User(name: String, age: Int) { private var name: String = "" private var age: Int = 0
init { println("初始化块") this.name = name this.age = age }
constructor(name: String) : this(name, 18) { println("一个参数的构造函数") }
constructor(age: Int) : this("xxin") { println("两个参数的构造函数") } }
|
继承
Kotlin
中的类默认是不可继承的,如果要使一个类可以被继承,需要在类名前添加open
关键字
类的继承使用:
关键字,Kotlin
中所有类默认继承Any
类
下面代码中,让IKun
类继承User
类,被继承的类User
之所以带有()
,是因为Kotlin
和java
一样,在类继承时子类的构造函数会调用父类的构造函数,如果父类没有定义构造函数,子类继承时应该调用父类的无参构造函数,所以被继承的类带有()
1 2 3
| class IKun : User() { }
|
如果父类有多个构造函数,子类只需要选择调用一个构造函数即可,具体选择哪个构造函数,在继承时通过()
中的参数指定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| open class User() { constructor(name: String) : this() { println("User的构造方法1") }
constructor(name: String, age: Int) : this(name) { println("User的构造方法2") } }
class IKun(name: String) : User() {
}
class IKun(name: String) : User(name) {
}
|
如果子类中只有次构造函数,没有主构造函数,那么被继承的类User
后不需要再带()
,构造函数中使用super
关键字调用父类的构造函数
1 2 3 4 5
| class IKun : User { constructor() : super() { println("IKun constructor") } }
|
接口
和java
一样,Kotlin
中的接口使用interface
关键字声明
1 2 3 4 5 6
| interface IKun { fun sing() fun dance() fun rap() fun basketball() }
|
实现接口使用:
,实现多个接口使用,
分隔,重写方法时,需要使用override
关键字
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class XiaoHeiZi : IKun { override fun sing() { println("我会唱") } override fun dance() { println("我会跳") } override fun rap() { println("我会rap") } override fun basketball() { println("我会篮球") } }
|
调用接口中的方法
1 2 3 4 5
| val iKun: IKun = XiaoHeiZi() iKun.sing() iKun.dance() iKun.rap() iKun.basketball()
|
数据类
Kotlin
中提供了数据类,使用data
关键字声明,会自动生成equals()
、hashCode()
、toString()
方法
1
| data class User(private val name: String, private val age: Int)
|
等同于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class User(private val name: String, private val age: Int) { override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is User) return false
if (age != other.age) return false if (name != other.name) return false
return true }
override fun hashCode(): Int { var result = age result = 31 * result + name.hashCode() return result }
override fun toString(): String { return "User(name='$name', age=$age)" } }
|
单例类
Kotlin
中提供了单例类,使用object
关键字声明,会自动生成一个实例,并且是线程安全的
1 2 3 4 5
| object Singleton { fun singletonTest() { println("singletonTest") } }
|
调用
1
| Singleton.singletonTest()
|
等同于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Singleton() { companion object { @Volatile private var instance: Singleton? = null
fun getInstance(): Singleton { if (instance == null) { synchronized(Singleton::class) { if (instance == null) { instance = Singleton() } } } return instance!! } } }
|
调用
1
| Singleton.getInstance().singletonTest()
|
Lambda表达式
Lambda
表达式的结构如下
1 2 3 4 5 6 7
| { 参数名1: 参数类型, 参数名2: 参数类型 -> 函数体 }
val lambda = { s1: String, s2: String -> println("${s1},我是练习时长两年半的个人练习生cxk") println("${s2}唱跳rap篮球") }
|
函数式接口
函数式接口是指只包含一个抽象方法的接口,在Kotlin
中,函数式接口可以使用fun interface
关键字声明
Java
中的函数式接口可以省略fun interface
关键字,或者使用@FunctionalInterface
注解声明
如果一个函数所需的参数是函数式接口
,那么可以直接将Lambda
表达式作为参数传递给函数
1 2 3 4 5 6 7 8 9 10 11 12
| fun interface Trainee { fun showTalent(s1: String, s2: String) }
class Producer (private val trainee: Trainee) { fun start() { trainee.showTalent("全民制作人大家好", "我喜欢") } }
|
创建全民制作人
对象时,需要传入个人练习生
的匿名类,如下
1 2 3 4 5 6
| Producer(object : Trainee { override fun showTalent(s1: String, s2: String) { println("${s1},我是练习时长两年半的个人练习生cxk") println("${s2}唱跳rap篮球") } }).start()
|
使用Lambda
表达式可以简化代码
1 2 3 4 5
| val lambda = { s1: String, s2: String -> println("${s1},我是练习时长两年半的个人练习生cxk") println("${s2}唱跳rap篮球") } Producer(lambda).start()
|
Lambda
表达式不必声明为变量,直接写入
1 2 3 4
| Producer({ s1: String, s2: String -> println("${s1},我是练习时长两年半的个人练习生cxk") println("${s2}唱跳rap篮球") }).start()
|
Lambda
表达式的参数类型可以省略,编译器会自动推导
1 2 3 4
| Producer({ s1, s2 -> println("${s1},我是练习时长两年半的个人练习生cxk") println("${s2}唱跳rap篮球") }).start()
|
如果Lambda
表达式是最后一个参数,那么可以将其放在括号外面;如果Lambda
表达式是唯一一个参数,那么可以省略括号
1 2 3 4 5 6 7 8 9 10 11
| Producer() { s1, s2 -> println("${s1},我是练习时长两年半的个人练习生cxk") println("${s2}唱跳rap篮球") }.start()
Producer { s1, s2 -> println("${s1},我是练习时长两年半的个人练习生cxk") println("${s2}唱跳rap篮球") }.start()
|
此外如果Lambda
表达式只有一个参数,参数可以使用it
关键字代替
1 2 3
| Producer { println("${it},我是练习时长两年半的个人练习生cxk,我喜欢唱跳rap篮球") }.start()
|
函数作为参数
Lambda
表达式可以作为参数传递给函数,如下,在子线程中执行传入的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| fun execute(func: (str: String) -> String) { if (pool == null) { pool = ThreadPoolExecutor( 5, 10, 10, TimeUnit.SECONDS, LinkedBlockingDeque(), Executors.defaultThreadFactory(), ThreadPoolExecutor.AbortPolicy() ) } pool!!.execute { func("cxk") } pool!!.shutdown() }
|
正常调用时
1 2 3
| execute(fun(name: String) { println("全民制作人大家好,我是练习时长两年半的个人练习生${name},我喜欢唱跳rap篮球") })
|
Lambda
表达式
通过Lambda
表达式简化代码
1 2 3
| execute { println("全民制作人大家好,我是练习时长两年半的个人练习生${it},我喜欢唱跳rap篮球") }
|
Lambda
表达式也可以作为函数的返回值,如下方法可以简化
1 2 3 4 5 6 7 8 9 10 11 12
| fun getFunc(): (str: String) -> Unit { return fun(str: String) { println("全民制作人大家好,我是练习时长两年半的个人练习生${str},我喜欢唱跳rap篮球") } }
fun getFunc(): (str: String) -> Unit { return { println("全民制作人大家好,我是练习时长两年半的个人练习生${it},我喜欢唱跳rap篮球") } }
|
调用时
1 2
| execute{ getFunc()(it) }
|