Kotlin学习笔记

读官方文档做的一些笔记

1. 字符串

使用三个引号(""")分界符括起来,内部没有转义并且可以包含换行以及任何其他字符

字符串模板

模板表达式以$开头,求出它后面的值

val s = "abc"
println("$s.length is ${s.length}") // 输出“abc.length is 3”

${'$'} //使用$本身

2. 类型的自动转化

如果一个不可变的局部变量或属性已经判断出为某类型,那么检测后的分支中可以直接当作该类型使用,无需显式转换

fun getStringLength(obj: Any): Int? {
    // `obj` 在 `&&` 右边自动转换成 `String` 类型
    if (obj is String && obj.length > 0) {    #不是 !is
      return obj.length
    }
    return null
}

3. if,for,while,when,in

// 1. if
fun maxOf(a: Int, b: Int) = if (a > b) a else b

fun foo(param: Int) {
    val result = if (param == 1) {
        "one"
    } else if (param == 2) {
        "two"
    } else {
        "three"
    }
}

// 2. for
val items = listOf("apple", "banana", "kiwifruit")
for (item in items) {
    println(item)
}

for (index in items.indices) {    //有索引
    println("item at $index is ${items[index]}")
}

for ((index, value) in array.withIndex()) {    //索引和值
    println("the element at $index is $value")
}

// 3. while
var index = 0
while (index < items.size) {
    println("item at $index is ${items[index]}")
    index++
}

// 4. when 必须有else 多个用逗号隔开
fun describe(obj: Any): String =
    when (obj) {
        1          -> "One"
        "Hello"    -> "Greeting"
        is Long    -> "Long"
        !is String -> "Not a string"
        in 'a'..'z', in 'A'..'Z' -> "It's a letter!"
        else       -> "Unknown"
    }

//可以将 when 所判断的表达式捕获到变量中
fun Request.getBody() =
    when (val response = executeRequest()) {
        is Success -> response.body
        is HttpError -> throw HttpException(response.status)
    }


// 5. in
for (x in 1..10 step 2) {
    print(x)
}
for (x in 9 downTo 0 step 3) {
    print(x)
}

4.  遍历 map/pair型list

for ((k, v) in map) {
    println("$k -> $v")
}

5. 区间

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) { …… }

6. list和map

val list = listOf("a", "b", "c")
val map = mapOf("a" to 1, "b" to 2, "c" to 3)
// 过滤list
val positives = list.filter { x -> x > 0 }
val positives = list.filter { it > 0 }

7. 扩展函数

fun String.spaceToCamelCase() { …… }
"Convert this to camelcase".spaceToCamelCase()

8. 与null相关

Kotlin将变量分为可以为Nullable类型 Non-Null类型,变量在声明时就要确定属于哪个阵营。变量默认Non-Null类型,如果想声明Nullable的变量,需要用“?”修饰  var str: String? = "Hello"

  • Nullable变量无法直接赋值给Non-Null变量,如果要赋值的话可以先判断是不是null,也可以用!!
var a: String? = "hello"
var b = "world"
if (a != null) {
    b == a
}

var a: String? = "hello"
var b = "world"
b = a!!  //使用“!!”方法要注意,当a为null时会抛出KotlinNullPointerException异常。

 Nullable变量进行操作时要带“?”,当变量为null时,不会出现异常,而是返回结果null

  • 与null相关的习惯写法

Nullable变量进行操作时要带“?”,当变量为null时,不会出现异常,而是返回结果null:

var name: String? = null
var len = name?.length
print(len == null)  //输出:true
val files = File("Test").listFiles()
println(files?.size ?: "empty")    //if not null and else 缩写

// 在可能会空的集合中取第一元素
val emails = …… // 可能会是空集合
val mainEmail = emails.firstOrNull() ?: ""

// if not null 执行代码
val value = ……
value?.let {
    …… // 代码会执行到此处, 假如data不为null
}

// 如果该值或其转换结果为空,那么返回 defaultValue
val mapped = value?.let { transformValue(it) } ?: defaultValue 

//可空布尔
val b: Boolean? = ……
if (b == true) {
    ……
} else {
    // `b` 是 false 或者 null
}

9. apply(对于配置未出现在对象构造函数中的属性非常有用)

val myRectangle = Rectangle().apply {
    length = 4
    breadth = 5
    color = 0xFAFAFA
}

10. 交换两个变量

var a = 1
var b = 2
a = b.also { b = a }

11. Kotlin 中的数字没有隐式拓宽转换,所以赋值比较都不可以。例如,具有 Double 参数的函数只能对 Double 值调用,而不能对 Float、 Int 或者其他数字值调用。显示转换是toXxxx()

数字里可以使用下划线让其更加易读

12. ===是引用相等, ==是值相等(equals)

13. 数组

arrayOf(1, 2, 3) 创建了 array [1, 2, 3]

arrayOfNulls() 可以用于创建一个指定大小的、所有元素都为空的数组

用接受数组大小以及一个函数参数的 Array 构造函数,用作参数的函数能够返回给定索引的每个元素初始值:

// 创建一个 Array<String> 初始化为 ["0", "1", "4", "9", "16"]
val asc = Array(5) { i -> (i * i).toString() }
asc.forEach { println(it) }

14. 尾递归优化

就是递归时只返回函数本身,没有其他计算,写成这样的递归在编译时会被自动优化,或者运行时会清除上次的栈信息,因为上次执行中的任何数据在下次执行时都是无关的

tailrec fun add(num:Int, result:Int):Int{
    if(num == 1){
        return 1
    } else {
        return add(num - 1, result + num)
    }
}

5. open

类要被继承,函数要被重写都要在前面加上open,重写要在函数前面加上override

16. 接口和类

abstract class Human{    //本质
    abstract fun eat()
}

interface Code{    //能力
    fun code()
}

class Man:Human(), Car{
    override fun code(){        
    }

    override fun eat(){
    }
}

18. sealed class

印章类

19. 泛型

协变(covariant):生产者,可以读数据但不能写数据,因为我们不知道什么对象符合那个未知的 E 的子类型。 E是一个协变类型的话只能作为返回类型,不能用作参数类型。Java里用<? extends E>,不可以add

逆变(controvariant):消费者,可以写数据但不能存数据。 Java里用<? super E>,不可以get

fun main(){
    var num: Number = 123
    var myClass = MyClass("abc", num)
    myTest(myClass)
}

class MyClass<out T, in M>(t: T, m: M){

    private var t: T = t
    private var m: M = m

    fun get(): T = this.t
    fun set(m: M) = {
        this.m = m
    }
}

fun myTest(myClass: MyClass<String, Number>){
    var myObject: MyClass<Any, Int> = myClass    //加上了 in 和 out 就可以引用
}

声名处协变,out出现在类声明的时候

如果泛型类只是将泛型类型作为其输入类型,那么我们就可以使用out。

如果泛型类只是将泛型类型作为其返回类型,那么我们就可以使用in。

对于 out 泛型来说,我们可以将子类型对象赋给父对象引用。对于 out 泛型,在取数据 get 的时候,子类型对象作为返回值可以传给符类型的返回值。

对于 in 泛型来说,我们可以将父类型对象赋给子对象引用。对于 in 泛型,在存数据 add 的时候,子类型对象作为参数可以传给父类型参数。

interface Producer<out T>{
    fun produce(): T
}

interface Consumer<in T>{
    fun consumer(item: T)
}

open class Fruit

open class Apple: Fruit()

class ApplePear: Apple()

//---------------------------------------

class FruitProducer: Producer<Fruit> {
    override fun producer(): Fruit{
        return Fruit()
    }
}

class AppleProducer: Producer<Apple> {
    override fun producer(): Apple{
        return Apple()
    }
}

class ApplePearProducer: Producer<ApplePear> {
    override fun producer(): ApplePear{
        return ApplePear()
    }
}

//----------------------------------------

class FruitConsumer: Consumer<Fruit>{
    override fun consume(item: Fruit){
        println()
    }
}

class AppleConsumer: Consumer<Apple>{
    override fun consume(item: Apple){
        println()    
    }
}

class ApplePearConsumer: ApplePearConsumer<ApplePear>{
    override fun consume(item: ApplePear){
        println()
    }
}

fun main(){
    val producer1: Producer<Fruit> = FruitProducer()
    val producer2: Producer<Fruit> = AppleProducer()
    val producer3: Producer<Fruit> = ApplePearProducer()

    val consumer1: Consumer<ApplePear> = ApplePearConsumer()
    val consumer2: Consumer<ApplePear> = AppleConsumer()
    val consumer3: Consumer<ApplePear> = FruitConsumer()

}

类型投影(使用处协变),因为out只能作为返回类型,in只能作为参数类型很不方便。出现在定义方法的时候

fun copy(from: Array<out Any>, to: Array<Any>){
    for(i in from.indices){
        to[i] = from[i]
    }
}

fun main(){
    val from: Array<Int> = arrayOf(1, 2, 3, 4)
    val to: Array<Any> = Array(4, {_ -> "hello"})    
    copy(from, to)
}

星投影

Star<out T> 如果T的上界是TUpper,那么Star<*>就相当于Star<out T>,这表示当T的类型未知时,可以从Star<*>当中安全地读取任何值

Star<in T> Star<*>就相当于Star<in Nothing>,这表示无法向其中写入任何值

Star<T> 如果T的上界是TUpper,那么Star<*>就相当于读取时的Star<out TUpper>,写入时的Star<in Nothing>(可以读,不能写)

class Star1<out T>{
}

class Star2<in T>{
    fun setValue(t: T){

    }    
}

class Star3<T>(private var t: T){
    fun setValue(t: T){

    }

    fun getValue(): T{
        return this.t
    }
}
fun main(){
    val star1: Star1<Number> = Star1<Int>()
    val star2: Star1<*> = star1

    val star3: Star2<Int> = Star2<Number>
    val star4: Star2<*> = star3
    //star.setValue(3) compile error

    val star5: Star3<String> = Star3<String>("hello")
    val star6: Star3<*> = star5

}

UpperBoundsClass<T: List<T>>  一个上界

UpperBoundsClass<T> where T: Comparable<T>, T: Any  两个上界

20. 可变参数可以借助于分散运算符(*)以具名函数的形式传递,可变参数通常为最后一个参数

test(strings = *arrayOf("a", "b", "c"))

fun test(vararg strings: String){
    strings.forEach(println(it))
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值