Kotlin学习笔记

1. 方法中的参数 有var/val 与没有的区别(fun A(var name: String) / fun A(name: String))???
   
   有var/val: 表示是当前类的一个属性
   无var/val: 表示是当前方法的一个参数
 
 
2. Kotlin中各种声明的执行顺序?

   初始化顺序依次如下:
   1. 构造函数里声明的属性
   2. 类级别的属性赋值
   3. init初始化代码块里的属性赋值和函数调用
   4. 次构造函数里的属性赋值和函数调用
 
 
3. 继承: 使用open关键字修饰的类和方法可以被继承, 否则类不能继承, 方法不能重写
 
4. inner class; 定义内部类, 在内部类中访问外部类, 需要显示使用this@xxx.yyy() (xxx是外部类名, yyy是外部类的方法名)

5. data class: 数据类
  
6. 拓展函数: fun AAA.bbb(){......} (AAA是需要拓展的类, bbb是拓展的方法)
   属性拓展: 同上

7. 操作符/关键字:

   ==: 比较得是内容
   ===: 比较的是内存堆上的对象

8.关键字相关

by lazy: 懒加载, 通过by关键字, 将xxx属性委托给lazy()里面的实例
lateinit: 延迟初始化
const: 用来修饰val (不能是var)常量
range: 一个值是否在一个取值范围里, 例如 4 in 0..10, 即4是否在0-10的范围内

apply: 对一个函数(对象(接收者)进行配置, 然后返回这个配置好的对象   ------> 返回配置好的对象(接收者)
let: 会将接收者传给lambda, 匿名函数执行完                ------> 返回lambda的最后一行
run: 类似apply                                       ------> 返回lambda的结果, 即布尔值true/false或者其他值
with: 需要传入一个参数 其他类似run
also: 类似let                                       ------> 返回配置好的对象
takeIf: 判断lambda的条件表达式, 如果是true:返回接收者对象, false:返回null
takeUnless: 与takeIf相反
take:
is: 类型判断
as: 类型转换

by: 实现委托, 类委托和属性委托, 可以更好的实现代理模式
interface Animal{                             
    fun bark()
}

class Cat: Animal{
    override fun fark(){
        println("喵喵")
    }
}

class Zoo(animal: Animal) : Animal by animal //将Zoo委托给他的参数 animal

fun main(args: Array<String>){
    val cat = Cat()
    Zoo(cat).frak()
}
输出结果: "喵喵"


map: 变换函数, 会遍历接收者集合中的每一个元素, 让百能唤起函数作用于集合中的每一个元素, 返回结果是包含已修改元素的集合, 会作为链上 下一个函数的输入
flatMap: 操作一个集合的集合, 可以将多个集合中的元素合并后返回一个包含所有元素的单一集合
filter: 过滤--> 例如可以将一个集合中包含"a"字母的元素拿出来形成一个新的集合, 该集合中的每一个元素都包含"a"

in : 父类泛型对象可以赋值给子类泛型对象
out: 子类泛型对象可以赋值给父类泛型对象

constructor(name: String){......}: 次构造器, 写在类中(如果写在类名后 则是主构造器)
object: 1. 对象表达式 2. 对象声明(object修饰的类为静态类, 里面的方法和变量也都为静态的)
companion object{} 伴生对象 在类中只能存在一个,即 {}中的方法和属性是静态的, 类中的其他属性和方法则不是静态的

? //可控类型 表示对象/属性可以null
?. //安全调用运算符 如果问号(?)前的值不为空可以执行点(.)后的方法, 否则返回null
?: //空合并操作符, A ?: B 即如果A是空, 返回B,否则返回A它本身
:: //函数引用, ::后面跟函数
!!: //当值为null就抛出异常, 不执行后面的方法

------> 在java调用kotlin方法 <------
@file:JvmName("xxx"): 在Kotlin文件最上面添加这个注释, 则可以不使用当前Kotlin文件名字, 而是使用这里定义的名字(xxx: 别名)
@JvmField: 在Kotlin文件中 属性上面添加这个注释, 那么在Java文件中可以直接使用这个属性, 而不用get/set
@JvmStatic: 在Kotlin文件中 方法上面添加这个注释, 那么在Java文件中可以直接使用这个方法, (静态调用 class.xx()  类.方法)
@JvmOverloads: 在Kotlin文件中 方法上面添加这个注释, 那么在Java文件中使用, 就可以强制实现重载, 传入不同数量的参数.
@Throws(IOException::class): 在Kotlin文件中 方法上面添加这个注释, 那么在Java文件中使用, 就必须要处理这个异常添加try{}catch()  (异常可以是任意异常)

Kotlin 泛型
泛型类:
制作一个万能的遥控器
class Controller<T>(){
    fun turnOn(obj: T){......}
    fun turnOff(obj: T){......}
}

电视遥控器:
val tvController = Controller<TV>()
val tv = TV()
tvController.turnOn(tv)
tvController.turnOff(tv)
电风扇遥控器:
val fanController = Controller<Fan>()
val fan = Fan()
fanController.turnOn(fan)
fanController.turnOff(fan)

泛型函数:
fun <T> turnOn(obj: T){......}
fun <T> turnOff(obj: T){......}

控制电视:
val tv = TV()
turnOn<TV>(tv)
turnOff<TV>(tv)
控制风扇:
val fan = Fan()
turnOn<Fan>(fan){......}
turnOff<Fan>(fan){......}

泛型的不变性:
招聘大学生的故事
open class Student() //学生类

class FemaleStudent: Student() //女学生类

class University<T>(val name: String){
    fun get(): T{......} //往外取, 表示招聘
    fun put(student: T){......}
}

开始招聘
lateinit var university: University<Student>

university = University<Student>("某大学")
val student: Student = university.get() //招聘(得到一个大学生)

错误写法:
university = University<FemaleStudent>("女子大学")
val student: Student = university.get()

reason: 
required: University<Student> 
Found: University<FemaleStudent>

那怎么可以执行上面的方式呢? 利用泛型的协变, 即 T 前加out (去掉了put()方法)
class University<out T>(val name: String){
    fun get(): T{......}
}

val university: University<Student> = University<FemaleStudent>("女子大学")
val student: Student = university.get()

泛型的逆变, 在T 前加in
open class Student()

class FemaleStudent: Student()

class Unitversity<T>(val name: String){
    fun get(): T{......}
    fun put(student: T){......} //这里是填志愿
}

val sister: FemaleStudent = FemaleStudent()
val university: University<FemaleStudent> = Unitversity<FemaleStudent>("女子大学")
university.put(sister)

那如果想报普通大学呢?
val sister: FemaleStudent = FemaleStudent()
val university: Unitversity<FemaleStudent> = Unitversity<Student>("普通大学")
university.put(sister)

报错:
Required: Unitversity<FemaleStudent>
Found: Unitversity<Student>

那怎么可以执行上面的方式呢? 利用泛型的逆变, 即 T 前加in (去掉了get()方法)
class University<in T>(val name: String){
    fun put(student: T){......}
}

val sister: FemaleStudent = FemaleStudent()
val university: University<FemaleStudent> = Unitversity<Student>("普通大学")
university.put(sister)

使用处型变(使用处协变, 使用处逆变)
open class Student()

class FemaleStudent: Student()

class University<T>(val name:String){
    fun get(): T{......}
    fun put(student: T){......}
}

使用处协变
fun useSiteCovariant(university: Unitversity<out Student>){
    val femaleStudent: Student? = university.get()
}

使用处逆变
fun useSiteCovariant(university: University<in FemaleStudent>){
    university.put(FemaleStudent())
}

扩展函数
1. 顶层扩展(本质: 就是Java的静态方法, 为当前类添加静态方法或者属性):
fun String.log(){ //为String 定义扩展函数
    println(this)
}

val String?.isNullOrBlank: Boolean //为String 定义扩展属性
        get() = this == null || this.isBlank()

2. 类内扩展:
class Host(val hostName: String){
    fun printlnHostName(){println(hostName)}
}

class Test(val host: Host, val port: Int){
    fun printlnPort(){println(port)}
    
    //在Test类中给Host增加一个扩展函数
    fun Host.printlnConnectionString(){
        printlnHostName() //Host类中的函数
        print(":")
        printPort() //Test类中的函数
    }
    
    //在Test类中给Host增加了一个属性
    val Host.isHomeEmpty: Boolean
        get() = hostName.isEmpty()
        
    fun test(){
        host.printlnConnectionString()
    }
}

//在别的地方调用Host类的扩展函数
fun main(){
    Host("").isHomeEmpty
    Host("").printlnConnectionString()
}
以上会报错, 因为Host的类的扩展在外面是无法访问的, 这与顶层扩展不同

顶层扩展: 不能定义在类内, 他的作用域是package级别, 能导包就能用(也就是说需要导包)
类内拓展: 定义在其他类内, 他的作用域是该类中, 优势是既能访问被扩展类(Host)也能访问他所在的类(Test)

扩展并没有实际修改被扩展的类, 因此我们仍然只能访问类中的public方法和属性. <<原理是 被扩展的类变成了扩展函数的参数>>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值