美文网首页
Kotlin进阶

Kotlin进阶

作者: 竖起大拇指 | 来源:发表于2021-06-30 09:47 被阅读0次

1.次级构造

class CodeView : TextView {
 constructor(context: Context): super(context)
}

2.主构造器

class CodeView constructor(context: Context) : TextView(context)
// 如果没有被「可⻅性修饰符」「注解」标注,那么 `constructor` 可以省略
class CodeView (context: Context) : TextView(context)

成员变量初始化可以直接访问到主构造参数

class CodeView constructor(context: Context) : TextView(context){
 val color = context.getColor(R.color.white)
}

3.init 代码块

主构造不能包含任何的代码,初始化代码可以放到 init 代码块中

class CodeView constructor(context: Context) : TextView(context) {
 init {
 //...
 }
}

在初始化的时候,初始化块会按照它们在「⽂件中出现的顺序」执⾏。

class CodeView constructor(context: Context) : TextView(context) {
 init {
 // ...
 }
 val paint = Paint() // 会在 init{} 之后运⾏
}

4.构造属性

在主构造参数前⾯加上 var/val 使构造参数同时成为成员变量

class User constructor(var username: String?, var password: String?, var code:
String?)

5.data class

数据类同时会⽣⽣成

  • toString()
  • hashCode()
  • equals()
  • copy() (浅拷⻉)
  • componentN() ...

6.相等性

  • == 结构相等(调用equals()比较)
  • === 引用(地址值)相等

7.解构

可以把⼀个对象「解构」成很多变量

val (code, message, body) = response

对应的java代码

val code = response.component1()
val message = response.component2()
val body = response.component3()

8.Elvis 操作符

可以通过 ?: 的操作来简化 if null 的操作

// lesson.date 为空时使⽤默认值
val date = lesson.date?: "⽇⽇期待定"
// lesson.state 为空时提前返回函数
val state = lesson.state?: return
// lesson.content 为空时抛出异常
val content = lesson.content ?: throw IllegalArgumentException("content
expected")

9.when操作符

when表达式可以接受返回值,多个分支相同的处理方式可以放在一起,用逗号分隔

val colorRes = when (lesson.state) {
 Lesson.State.PLAYBACK, null -> R.color.playback
 Lesson.State.LIVE -> R.color.live
 Lesson.State.WAIT -> R.color.wait
}

when 表达式可以⽤来取代 if-else-if 链。如果不提供参数,所有的分⽀条件都是布尔表达式

val colorRes = when {
 (lesson.state == Lesson.State.PLAYBACK) -> R.color.playback
 (lesson.state == null) -> R.color.playback
 (lesson.state == Lesson.State.LIVE) -> R.color.live
 (lesson.state == Lesson.State.WAIT) -> R.color.wait
 else -> R.color.playback
}

10.operator

通过 operator 修饰「特定函数名」的函数,例如 plus 、 get ,可以达到重载运算符的效果

11.lambda

如果函数的最后⼀个参数是 lambda ,那么 lambda 表达式可以放在圆括号之外:

lessons.forEach(){ lesson : Lesson ->
 // ...
}

如果你的函数传⼊参数只有⼀个 lambda 的话,那么⼩括号可以省略的:

lessons.forEach { lesson : Lesson ->
 // ...
}

如果 lambda 表达式只有⼀个参数,那么可以省略,通过隐式的 it 来访问

lessons.forEach { // it
 // ...
}

12.循环

通过标准函数 repeat() :

repeat(100) {
 //..
}

通过区间:

for (i in 0..99) {
}
// until 不包括右边界
for (i in 0 until 100) {
}

13.infix函数

必须是成员函数或扩展函数
必须只能接受⼀个参数,并且不能有默认值

// until() 函数的源码
public infix fun Int.until(to: Int): IntRange {
 if (to <= Int.MIN_VALUE) return IntRange.EMPTY
 return this .. (to - 1).toInt()
}

14.嵌套函数

Kotlin 中可以在函数中继续声明函数

fun func(){
 fun innerFunc(){

 }
}
  • 内部函数可以访问外部函数的参数
  • 每次调⽤时,会产⽣⼀个函数对象

15.函数简化

可以通过符号=简化原本直接return的函数

fun get(key :String) = SP.getString(key,null)

16.函数参数默认值

可以通过函数参数默认值来代替 Java 的函数重载

// 使⽤ @JvmOverloads 对 Java 暴露重载函数
@JvmOverloads
fun toast(text: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
 Toast.makeText(this, text, duration).show()
}

17.扩展

  • 扩展函数可以为任何类添加上⼀个函数,从⽽代替⼯具类
  • 扩展函数和成员函数相同时,成员函数优先被调⽤
  • 扩展函数是静态解析的,在编译时就确定了调⽤函数(没有多态)

18.函数类型

函数类型由「传⼊参数类型」和「返回值类型」组成,⽤「 -> 」连接,传⼊参数需要⽤「 () 」,如果
返回值为 Unit 不能省略 函数类型实际是⼀个接⼝,我们传递函数的时候可以通过「 ::函数名 」,或者
「匿名函数」或者使⽤ 「 lambda 」

19.内联函数

  • 内联函数配合「函数类型」,可以减少「函数类型」⽣成的对象
  • 使⽤ inline 关键字声明的函数是「内联函数」,在「编译时」会将「内联函数」中的函数体直接插⼊到调⽤处。
  • 所以在写内联函数的时候需要注意,尽量将内联函数中的代码⾏数减少!

20.具体化的类型参数

因为内联函数的存在,我们可以通过配合 inline + reified 达到「真泛型」的效果

val RETROFIT = Retrofit.Builder()
 .baseUrl("https://api.hencoder.com/")
 .build()
inline fun <reified T> create(): T {
 return RETROFIT.create(T::class.java)
}
val api = create<API>()

Reified类型参数仅适用于函数(或具有get()函数的扩展属性),并且仅适用于声明为inline内联的函数。这是一个例子:

inline fun <reified T> Any.isInstanceOf(): Boolean = this is T
当您将函数标记为inline时,编译器会把实现内联函数的字节码插入到每次调用发生的地方。这就是reified类型的工作原理 - 具体实际类型在调用地方是已经知道的,因此在调用x.isInstanceOf<String>()有效地把x编译为String.

reified类型实化参数经常被使用到的几个地方

假设我们有一个User类,以及我们想要读取的JSON字符串

data class User(val first: String, val last: String)

val json = """{
      "first": "Sherlock",
      "last": "Holmes"
    }""

在Java序列化库(如Gson)中,当您想要反序列化该JSON字符串时,您最终必须将Class对象作为参数传递,以便Gson知道您想要的类型。

User user = new Gson().fromJson(getJson(), User.class);

现在,让我们一起展示reified类型实化参数的魔法 我们将创建一个非常轻量级的扩展函数来包装Gson方法:

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

现在,在我们的Kotlin代码中,我们可以反序列化JSON字符串,甚至根本不需要传递类型信息!

val user: User = Gson().fromJson(json)

Kotlin根据它的用法推断出类型 - 因为我们将它分配给User类型的变量,Kotlin使用它作为fromJson()的类型参数。或者,您可以使类型推断其他的类:

val user = Gson().fromJson<User>(json)

在这种情况下,从传递给fromJson()的类型参数推断出user类型。

21.抽象属性

在 Kotlin 中,我们可以声明抽象属性,⼦类对抽象属性重写的时候需要重写对应的 setter/getter

22.属性委托

有些常⻅的属性操作,我们可以通过委托的方式,让它只实现一次,例如:

  • lazy延迟属性:值只在第一次访问的时候计算
  • observable可观察属性:属性发生改变时的通知
  • map集合:将属性存在一个map中
    对于一个只读属性(即val声明的),委托对象必须提供一个名为getValue()的函数
    对于一个可变属性(即 var 声明的),委托对象同时提供setValue()、getValue()函数

23.类委托

可以通过类委托的模式来减少继承类委托的,编译器会优先使用自身重写的函数,而不是委托对象的函数

相关文章

网友评论

      本文标题:Kotlin进阶

      本文链接:https://www.haomeiwen.com/subject/nnbkultx.html