Kotlin学习之05

发布时间:2024年01月06日

类构造器

class Person(var age: Int(类内全局可见), name: String(init块可见,属性初始化))

init块可以有多个,可以分开写,最终会合并执行

init块可以直接访问构造方法中的参数

定义了主构造器后在类内部再定义的构造器都被称为副构造器

constructor(d: Int): this(d, "")

副构造函数后可调用主构造函数或其他副构造函数,类似java的构造函数重载。

类的可见性

public : 公开(默认)

internal:模块内可见

protected:类内及子类可见

private:类或者文件内可见

延迟初始化

可空类型(使用?修饰)

lateinit:初始化与声明分离,可在后续阶段进行初始化,但是需要注意的是,lateinit会让编译器忽略变量的初始化,不支持int等基本数据类型

lazy:懒加载,初始化与声明内聚,属性首次被访问时执行初始化语句,lazy属性代理,代理了修饰的属性的getter方法。lazy是一个比较推荐的延迟初始化方式,实际上它是一个属性代理。

lazy相当于使用by将属性的get方法代理了,当使用时,才去调用对应的初始化方法。

接口代理

接口代理其实就是可以把一些没必要实现的接口方法隐藏起来,而不用每一个接口都要写一下。其中by关键字右边就是实际代理对象,它是构造函数中的一个属性,by关键字左边是代理类对象实现的接口。

使用前

class ApiWrapper(var api : Api): Api {
    override fun a() {
        api.a()
    }

    override fun b() {
        api.b()
    }

    override fun c() {
        println("c is called")
        api.c()
    }
}

interface Api {
    fun a();
    fun b();
    fun c();
}

使用后

class ApiWrapper(val api : Api): Api by api {
    
    override fun c() {
        println("c is called")
        api.c()
    }
}

interface Api {
    fun a();
    fun b();
    fun c();
}

kotlin单例

只需要在类前面添加object关键字,object定义类等于java的饿汉式单例模式

object类不能定义构造函数,但可以定义init函数

object修饰的类内部方法相当于静态方法,该静态方法是伪静态的,也就是内部会生成一个静态的成员对象,对象的方法调用实际上是调用内部静态成员对象的方法,只有在方法上添加@JvmStatic才会真正的生成静态方法。

@JvmField:使用该注解则不会生成getter/setter方法

内部类

kotlin中类内部的class前面不写修饰符默认就是静态内部类:

class MyClass {}

加inner修饰符就是java中的普通内部类,会持有外部类的对象引用

object类内部的object类默认是静态的,不存在非静态的情况,不能定义成inner

匿名内部类

实际上就是省略了类名直接实现接口

fun main() {

? ? ? ? object : Runnable {

????????}

}

匿名内部类可用继承多个接口

fun main() {

? ? ? ? object : Runnable,Cloneable{

????????}

}

数据类

kotlin中提供一个data关键字,data修饰的类就是一个数据类

data class Person(val id : Long, val name : String, val age : Int)

与java的bean相比,kotlin的data类不能被继承,并且属性要全部写到构造函数当中,没有无参的构造函数。

解构

解构声明允许将一个对象的字段拆解为值或者变量,其内部原理是自动生成了componeN函数。

例如:val p = Person(1, "hello", 20)

val (id, name, age) = p;

使用解构后,可以直接用字段获取值:id,name,age访问数据

data类本身不能被继承,通过查看编译后的代码可以看出,本身被final关键字所修饰。

枚举类

enm class State {

? ? ? ? Idle, Busy

}

枚举类不可继承其他类,但是可以实现接口,可以定义扩展函数

密封类:sealed

密封类是一种特殊抽象类,子类必须定义在自身相同的文件中,个数是有限的

内联类:inline

内联类是对某一个类型的包装,类似于Java装箱类型,编译器会尽可能使用被包装的类型进行优化。

限制:主构造器必须有且仅有一个只读属性,不能定义有backing-field的其他属性,被包装类型不能是范型,不能继承父类也不能被继承,但可以实现接口

Json for Kotlin

moshi

新一代Json解析库Moshi使用及原理解析 - 掘金

moshi本身使用步骤比gson复杂得多,但同时其功能也更加强大

使用步骤

配置plugins:apply plugins: 'kotlin-kapt'

引入moshi:implementation("com.squareup.moshi:moshi-kotlin:1.11.0")

? ? ? ? ? ? ? ? ? ? kapt("com.squareup.moshi:moshi-kotlin-codegen:1.11.0")

使用时,需要在data class上面添加注解:@JsonClass(generateAdapter = true)

开始序列化与反序列化

@JsonClass(generateAdapter = true)
data class moshi(val a : String, val b : Int, val c : Boolean)

fun main() {
    val ms = Moshi.Builder().build()
    val jsonAdapter = ms.adapter(moshi::class.java)
    val json = jsonAdapter.toJson(moshi("aaa", 222, false))

    println("json:${json}")

    val mss = jsonAdapter.fromJson("""{"a":"111", "b":333,"c":true}""")
    println("a:${mss?.a}")
    println("b:${mss?.b}")
    println("c:${mss?.c}")
}

如果data属性本身给了默认值,则序列化时,会使用该值,否则使用默认值

moshi在使用json反序列化KClass时,如果field是Nullable类型,则可以填入Null,如果是NonNull类型,则在填入Null时会立即抛出异常。

JsonToKotlinClass:该插件用于根据Json字符串生成kotlin的data class

泛型

//泛型
fun <T> maxOf(a: T, b: T): T {
    return a;
}

//泛型约束
fun <T : Comparable<T>> maxOf(a: T, b: T): T {
    return if (a > b) a else b
}

//多个约束
fun <T> callMax(a : T, b: T) where T : Comparable<T>, T:() -> Unit {
    if (a > b) a() else b()
}

//多个泛型参数以及约束
fun <T, R> callMax(a: T, b: T) : R where T : Comparable<T>, T:() ->R, R:Number {
    return if(a > b) a() else b()
}

//协变,out标识协变
interface Book

interface EduBook : Book

class BookStore<out T : Book> {
    fun getBook() : T {

    }
}

fun covariant() {
    val eduBookStore : BookStore<EduBook> = BookStore<EduBook>()
    val bookStore : BookStore<Book> = eduBookStore

    val book : Book = bookStore.getBook()
    val eduBook : EduBook = eduBookStore.getBook();
}

//子类兼容父类
//存在协变点的类的泛型参数必须声明为协变或不变
//当泛型类作为泛型参数类实例的生产者时使用协变
//使用out关键字修饰的泛型就是协变,返回值为协变泛型类型的称为协变点

open class Waste

class DryWaste : Waste()

class Dustbin<in T : Waste> {
    fun put(t : T) {

    }
}

fun contravariant() {
    val dustbin : Dustbin<Waste> = Dustbin<Waste>()
    val dryWasteDustbin : Dustbin<DryWaste> = dustbin;

    val waste = Waste()
    val dryWaste = DryWaste()

    dustbin.put(waste)
    dustbin.put(dryWaste)

    dryWasteDustbin.put(dryWaste)
}

//逆变
//子类兼容父类
//存在逆变点的类的泛型参数必须声明为逆变或不变
//当泛型类作为泛型参数类实例的消费者时用逆变
//使用in关键字修饰的泛型就是逆变,作为函数输入参数的泛型称为逆变点。逆变主要是指输入的参数类型,是消费者。并且消费者的继承关系跟协变是相反的

//星投影
//可用在变量类型声明的位置
//可以描述一个未知的类型
//所替换的类型在协变点返回泛型参数上限类型(也即返回的是类型限制的类型),在逆变点接收泛型参数下限类型(也即限制类型的各种子类)
//*不能直接或间接应用在属性或函数上,也即最终确认类型的地方,可以用于未确定对象类型的地方,比如val queryMap: QueryMap<*, *>
//
fun main() {
    val queryMap : QueryMap<*, *> = QueryMap<String, Int>();
    queryMap.getKey()
    queryMap.getValue()

    val f : Function<*, *> = Function<Number, Any>()

    if (f is Function) {
        (f as Function<Number, Any>).invoke(1, Any())
    }
    maxOf(1, 3)
    HashMap<String, List<*>>()
    val hashMap : HashMap<*, *> = HashMap<String, Int>()

}

class QueryMap<out K: CharSequence, out V : Any> {
    fun getKey() : K = TODO()
    fun getValue() : V = TODO()
}

class  Function<in P1, in P2> {
    fun invoke(p1 : P1, p2 : P2) = Unit
}

内联特化

inline fun <reified T> genericMethod(t : T) {

? ? ? ? val t = T()

? ? ? ? val ts = Array<T>(3){ TODO() }

? ? ? ? val jClass = T::class:java

? ? ? ? val list = ArrayList<T>()

? ? ? ? if(list is List<*>) {

? ? ? ? ? ? ? ? println(list.joinToString())

????????}

}

内联特化在调用的地方会替换到调用处,因此这时类型是确定的了。即已经特化成某个具体类型。通过fun前面的关键字inline和泛型参数T前面的reified参数两个来指定泛型参数在调用处实例化。

class Person(val age: Int, val name: String)

inline fun <reified T> Gson.fromJson(json: String): T = fromJson(json, T::class.java)

fun main() {

? ? ? ? val gson = Gson()

? ? ? ? val person2 : Person = gson.fromJson("""{"age":18,"name":ABC"}""") //类型推导

? ? ? ? val person3 : Person = gson.fromJson<Person>("""{"age":18,"name":"ABC"}""")//泛型参数

}

typealias OnConfirm = () -> Unit
typealias OnCancel = () -> Unit

private val EmptyFunction = {}

open class Notification(val title: String, val content: String)

class ConfirmNotification(title: String, content: String, val onConfirm: OnConfirm, val onCancel: OnCancel) :
    Notification(title, content)

interface SelfType<Self> {
    val self: Self
        get() = this as Self
}

open class NotificationBuilder<Self : NotificationBuilder<Self>> : SelfType<Self> {

    protected var title: String = ""
    protected var content: String = ""

    fun title(title: String): Self {
        this.title = title
        return self;
    }

    fun content(content: String): Self {
        this.content = content
        return self
    }

    open fun build() = Notification(this.title, this.content)

}

class ConfirmNotificationBuilder : NotificationBuilder<ConfirmNotificationBuilder>() {
    private var onConfirm: OnConfirm = EmptyFunction
    private var onCancel: OnCancel = EmptyFunction
    fun onConfirm(onConfirm: OnConfirm): ConfirmNotificationBuilder {
        this.onConfirm = onConfirm;
        return this
    }

    fun onCancel(onCancel: OnCancel): ConfirmNotificationBuilder {
        this.onCancel = onCancel;
        return this
    }

    override fun build() = ConfirmNotification(title, content, onConfirm, onCancel)
    
}

fun main() {
    ConfirmNotificationBuilder()
        .title("Hello")
        .onCancel { 
            println("onCancel")
        }
        .onConfirm { 
            println("onConfirmed")
        }
        .build()
        .onConfirm
}
//如果不定义SelfType类型,则子类在调用ConfirmNotificationBuilder().title("hello")之后,就不能再调用子类的onCancel方法,因为返回的是父类型,但实际运行时这个类型是子类型。
实例:基于泛型实现的Model实例的注入
import java.util.concurrent.ConcurrentHashMap
import kotlin.reflect.KProperty

abstract class AbsModel {
    init {//这就相当于初始化的时候就将类添加到Models上
        Models.run { this@AbsModel.register() }
    }
}

/***
 * 这三个类主要是继承了AbsModel类,
 */
class DatabaseModel : AbsModel() {
    fun query(sql : String) : Int = 0
}

class NetworkModel : AbsModel() {
    fun get(url : String) : String = """{"code":0}"""
}

class  SpModel : AbsModel() {
    init {//增加一个SpModel2
        Models.run { register("SpModel2")
        println("?????")}
    }

    fun hello() = println("Hello World")
}

//单例
object Models {
    //保存AbsMode对象,Concurrent表示是带同步锁的
    private val modelMap = ConcurrentHashMap<String, AbsModel>()

    //注入类
    fun  AbsModel.register(name : String = this.javaClass.simpleName) {
        modelMap[name] = this;
    }

    //创建扩展函数,将返回值转换为实际的对象,这里是利用了扩展函数,将传进来的字符串转换成对象
    fun <T:AbsModel> String.get() : T {
        return modelMap[this] as T
    }

}

fun initModel() {
    DatabaseModel()
    NetworkModel()
    SpModel()
    //创建对象,通过init方法注入到委托
}

//单例
object ModelDelegate {
    operator fun <T:AbsModel> getValue(thisRef : Any, property : KProperty<*> ):T {
        return Models.run {
            property.name.capitalize().get()
        }
    }
}

class MainViewModel {
    //利用代理,将对象的获取通过委托实现
    val databaseModel : DatabaseModel by ModelDelegate
    val networkModel : NetworkModel by ModelDelegate
    val spModel : SpModel by ModelDelegate
    val spModel2 : SpModel by ModelDelegate
}

fun main() {
    initModel()
    val mainViewModel = MainViewModel()
    mainViewModel.databaseModel.query("select * from user").let { println() }
    mainViewModel.networkModel.get("http://www.baidu.com").let(::println)
    mainViewModel.spModel.hello()
    mainViewModel.spModel2.hello()
}

文章来源:https://blog.csdn.net/Dragonlongbo/article/details/134795454
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。