Kotlin学习记录
1、当一个函数中只有一行代码时,可以不用编写函数体。
例子:
fun largerNumber(num1:Int,num2:Int){
return max(num1,num2)
}
fun largerNumber(num1:Int,num2:Int):Int = max(num1,num2)
2、类型推导机制:因为max(num1,num2)函数返回的是一个Int值,而且函数尾部用等于号跟max()函数
连接,所以Kotlin可以推导出largerNumber的返回值也是Int类型,所以就不用显式地声明返回值类型。
例子:
fun largerNumber(num1:Int,num2:Int) = max(num1,num2)
3、当Lambda参数是函数的唯一一个参数的话,可以将函数的括号省略
例子:
val maxLengthFruit = list.maxBy({fruit: String -> fruit.length})
val maxLengthFruit = list.maxBy(fruit: String -> fruit.length)
4、Lambda表达式中的参数列表大多数情况下不必声明参数类型
val maxLengthFruit = list.maxBy(fruit -> fruit.length)
5、当lambda表达式的参数列表只有一个参数时,不必声明参数名,可以用it关键字来代替
val maxLengthFruit = list.maxBy(it.Length)
6、一个泛型类或者泛型接口中的方法,它的参数列表是接收数据的地方,因此可以称它为in位置,而它的返回值是输出数据的地方
,因此可以称它为out位置
条件语句:
1、if
fun largerNumber(num1:Int,num2:Int):Int{
var value = 0
if(num1>num2) {
value = num1
} else {
value = num2
}
}
if语句可以有返回值
fun largerNumber(num1:Int,num2:Int) :Int {
var value = if (num1 > num2) {
num1
} else {
num2
}
return value
}
value也是多余:
fun largerNumber(num1:Int,num2:Int) :Int {
return if (num1 > num2) {
num1
} else {
num2
}
}
再进一步简化:
fun largerNumber(num1:Int,num2:Int) = if (num1 > num2) num1 else num2
2、when
fun getScore(name: String) = when(name) {
"Tom" -> 86
"JIm" -> 73
"Jack" -> 91
"Hob" -> 84
"Jessica" -> 76
else -> 0
}
is 相当于 instance of
不带参数的when
fun getScore(name: String) = when {
name.startWith("Tom") -> 86
name == "Jack" -> 65
else -> 0
}
3、循环 for-in
区间:
val range = 0..10 相当于:[0,10]
val range = 0 until 10 相当于:[0,10)
val range = 10 downTo 0 相当于:[10,0]
for (i in 0..10) {
println(int)
}
for (i in 0 until 10 step 2) {
println(i)
}
继承
Kotlin中的任何一个非抽象类默认不可以被继承
声明可以被继承的类:
open class Person {
...(存在一个默认的无参数构造函数,跟java一样)
}
构造函数
主构造函数
class Student(val son: String,val grade: Int) {
}
在主构造函数中写逻辑:
class Student(val son: String,val grade: Int) {
init {
...
}
}
次构造函数(一般不用)
class Student(val son: String,val age: Int) {
constructor(name: String) : this(name,0)
constructor(age: Int) ; this("",age)
}
可以没有主构造函数,然后继承时就不用写括号:
class Student : Person {
constructor(name: String):super(name) {}
}
接口
实现接口用,
接口允许默认实现
interface Study {
fun readBook()
fun doHomeWork() {
println("do homework")
}
}
修饰符
默认public
private:只对当前类内部可见
protected:表示只对当前类及其子类可见
internal:只对同一模块中的类可见
单例类:
object HttpUtil {
...
}
集合的创建与遍历
val list = listOf("Apple","Banana","Orange")
val list = mutableListOf("Apple","Banana","Orange")
val map = mapOf("Apple" to 1,"Banana" to 2,"Orange" to 3)
for ((fruit,number) in map) {
...
}
Lambda表达式语法结构:
{参数名1:参数类型, 参数名2:参数类型, -> 函数体}
函数式API
val list = listOf("Apple","Banana","Orange")
val maxLengthFruit = list.maxBy {it.length}
val lambda = {fruit: String -> fruit.length}
val maxLengthFruit = list.maxBy(lambda)
简化:
去掉lambda变量:
val maxLengthFruit = list.maxBy({fruit: String -> fruit.length})
当Lambda参数是函数的唯一一个参数的话,可以将函数的括号省略:
val maxLengthFruit = list.maxBy(fruit: String -> fruit.length)
Lambda表达式中的参数列表大多数情况下不必声明参数类型
val maxLengthFruit = list.maxBy(fruit -> fruit.length)
当lambda表达式的参数列表只有一个参数时,不必声明参数名,可以用it关键字来代替
val maxLengthFruit = list.maxBy(it.length)
list.map {it.toUpperCase} 转成大写
list.filter(it.length <= 5) 过滤数据
list.any {it.length <= 5} 集合中至少存在一个元素满足给定条件(返回true或false)
list.all {it.length <= 5} 集合中的所有元素是否都满足给定条件(返回true或false)
Java函数式API的使用
在Kotlin中调用Java方法时也可以使用函数式API,不过这有一定条件限制。即,如果我们在Kotlin中调用一个Java方法,
并且该方法接收一个Java单抽象接口参数,就可以使用函数式API。
例子:
public interface Runnable {
void run();
}
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("");
}
}).start();
Kotlin版本:
Thread(object : Runnable {
override fun run(){
println("")
}
}).start()
简化代码:
Thread(Runnable {
println("")
}).start()
Thread( {
println("")
}).start()
Thread {
println("")
}.start()
可空系统
String表示不可为空的字符串
String?表示可为空的字符串
判断辅助工具
if(a != null) {
a.do()
}
a?.do()表示当a对象为空时什么也不做,不为空时调用do()
?:操作符
这个操作符的左右两边都接收一个表达式,如果左边表达式的结果不为空就返回左边表达式的结果,否则就返回右边表达式的结果
例子:
val c = if (a != null) {
a
} else {
b
}
val c = a ?: b
fun getTextLength(text: String?) = text?.length ?: 0
非空断言: val upperCase = content!!.toUpperCase()
let函数:将原始调用对象作为参数传递到Lambda表达式中
obj.let{obj2 ->
...
}
fun doStudy(study: Study?) {
study?.let {
it.readBooks()
}
}
字符串内嵌
"hello,${obj.name}"
函数的参数默认值
fun printParam(num: Int = 100,str: String) {
print("num is $num , str is $str")
}
fun main() {
printParam( str = "world", num = 123)
}
标准函数
with
val result = with(obj) {
}
run
跟with类似
val result = obj.run {
...
}
apply
跟前两个类似
val result = obj.apply {
}
定义一个类似静态方法的方法(伴生方法)
class HttpUtil {
companion object {
fun staticMethod() {
}
}
}
延迟初始化
private lateinit var adapter: MsgAdapter
避免重复初始化
if (!::adapter.isInitialized) {
...
}
密封类
可继承,当Kotlin编译器会自动检查密封类有哪些子类,并强制要求将每一个子类所对应的条件全部处理
sealed class Result
class Success(val msg: String): Result()
class Failure(val error: String): Result()
扩展函数
ClassName.method()
运算符重载
operator
class Obj {
operator fun plus(obj: Obj): Obj {
}
}
例子:
class Money(val value: Int) {
operator fun plus(money: Money): Money {
val sum = value + money.value
return Money(sum)
}
}
val money1 = Money(5)
val money2 = Money(10)
val money3 = money1 + money2
println(money3.value)
多重重载
class Money (val value: Int) {
operator fun plus(money: Money) {
...
}
operator fun plus(newValue: Int): Money {
val sum = value + newValue
return Money(value)
}
}
高阶函数
如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个函数,那么这个函数就被称为高阶函数
函数类型:(String,Int) -> Unit
->的左边是接收的参数的类型;右边是函数的返回值类型,Unit表示没有返回值,相当于void
fun example(func: (String,Int) -> Unit) {
func("hello",123)
}
高阶函数的例子
fun num1AndNum2(num1: Int,num2: Int,operation: (Int,Int) -> Int): Int {
val result = operation(num1,num2)
return result
}
调用高阶函数
fun plus(num1: Int,num2: Int): Int {
return num1 + num2
}
fun minus(num1: Int,num2: Int) {
return num1 - num2
}
fun main() {
val num1 = 100
val num2 = 80
val result1 = num1AndNum2(num1 , num2 , ::plus)
val result2 = num1AndNum2(num1 , num2 , ::minus)
}
用lambda表达式写
fun main() {
val num1 = 100
val num2 = 80
val result1 = num1AndNum2(num1,num2) { n1,n2 ->
n1 + n2
}
val result2 = num1AndNum2(num1,num2) { n1,n2 ->
n1 - n2
}
}
内联函数
inline fun do() {
...
}
inline fun inlineTest(block1: () -> Unit , noinline block2: () -> Unit) {
}
内联函数与非内联函数的区别
内联函数所引用的Lambda表达式是可以用return关键字返回的,而非内联函数只能局部返回
为什么使用noinline(取消内联)
因为内联的函数类型参数在编译的时候会被进行代码替换,因此它没有真正的参数属性。非内联的函数类型参数可以自由地
传递给其它任何函数,因为它就是一个真实的参数。
内联函数的好处
Kotlin编译器会将内联函数中的代码在编译的时候自动替换到调用它的地方,这样就不存在运行时的开销了
crossinline(什么时候用?在高阶函数中创建另外的Lambda或者匿名类的实现时)
声明crossinline后,就无法在调用runRunnable函数时的Lambda表达式中使用return关键字进行函数返回了
vararg可变参数列表
泛型类
class MyClass<T> {
fun method(param: T) {
return param
}
}
泛型方法
class MyClass {
fun <T> method(param: T) {
return param
}
}
fun <T> T.build(block: T.() -> Unit): T {
block()
return this
}
委托 by
类委托
将一个类的具体实现委托给另一个类去完成
委托属性
将一个属性(字段)的具体实现委托给另一个类去完成
懒加载
by lazy {
...
}
infix函数
if("HelloWorld" startWith "Hello") {
...
}
infix fun String.beginWith(prefix: String) = startWith(prefix)
if("HelloWorld" beginWith "Hello") {
}
限制:
1、不能定义成顶层函数,必须是某个类的成员函数
2、必须且只能接受一个参数,参数类型没有限制
利用内联函数对泛型实化
inline fun <reified T> getGenericType() {
}
应用
inline fun <reified T> startActivity(context: Context) {
context.startActivity(Intent(context,T::class.java))
}
startActivity<TestActivity>(context)
传参数
inline fun <reified T> startActivity(context: Context,block: Intent.() -> Unit) {
val intent = Intent(context,T::class.java)
intent.block()
context.startActivity(intent)
}
startActivity<TestActivity>(context) {
putExtra("param1","data")
putExtra("param2",123)
}
泛型协变
定义:假如定义了一个MyClass<T>的泛型类,其中A是B的子类型,同时MyClass<A>又是MyClass<B>的子类型,
那么就可以说MyClass在T这个泛型上是协变的。
用out关键字修饰泛型,泛型不能出现在in位置上,只能在out位置上
泛型逆变
in