IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android—Kotiln基础教程(七) -> 正文阅读

[移动开发]Android—Kotiln基础教程(七)

前言

在上一篇中,讲解了Kotlin对应的对象,接口,抽象类相关的知识点。在这一篇中,将会讲解Kotlin对应的泛型、扩展函数。

话不多说,直接开始!

1. 泛型

1.1 单泛型参数

open class Human(val age: Int)

class Boy(val name: String, age: Int) : Human(age)
class Man(val name: String, age: Int) : Human(age)
class Dog(val weight: Int)

class MagicBox<T>(item: T) {
    var available = false
    private var subject: T = item
    fun fetch(): T? {
        // takeIf 如果表达式成立,返回 使用者 subject 对象,否则返回null 对象
        return subject.takeIf { available }
    }
}


fun main{
    val box1: MagicBox<Boy> = MagicBox(Boy("Jack", 20))
    val box2: MagicBox<Dog> = MagicBox(Dog(12))

    println("box1 $box1")
    box1.available = true

    box1.fetch()?.run {
        println("this is ${this.javaClass.name} your name = $name")
    }

    println("box2 $box2")
    box2.available = true

    box2.fetch()?.run {
        println("this is ${this.javaClass.name} your weight = $weight")
    }
}

运行效果

box1 MagicBox@51016012
this is Boy your name = Jack
box2 MagicBox@29444d75
this is Dog your weight = 12

这个使用方式和java类似,使用方式也挺简单的,从头看到这的小伙伴,这点代码相信能够直接一眼而过,直接下一个!

1.2 多泛型参数

1.2.1 示例一

open class Human(val age: Int)

class Boy(val name: String, age: Int) : Human(age)
class Man(val name: String, age: Int) : Human(age)
class Dog(val weight: Int)

class MagicBox<T>(item: T) {
    var available = false
    private var subject: T = item
   // fun fetch(): T? {
   //     // takeIf 如果表达式成立,返回 使用者 subject 对象,否则返回null 对象
   //     return subject.takeIf { available }
   // }

    fun <R> fetch(subjectModFunction: (T) -> R): R? {
        return subjectModFunction(subject).takeIf { available }
    }
}

fun main{
    val box: MagicBox<Boy> = MagicBox(Boy("Jack", 20))
    box.available = true
    val man = box.fetch() {
        Man(it.name, it.age.plus(10))
    }
    man?.let { println("${it.name},${it.age}") }
}

运行效果

Jack,30

现在我们看到,这次使用 了MagicBox里的fun <R> fetch方法,在这个方法里拥有两个泛型:一个是T,一个是R,其中T泛型,我们知道是由外部传入而决定的;而R泛型,确实由return subjectModFunction(subject).takeIf { available }这句代码决定。

如果说available为true时,那么R类型就为subjectModFunction方法返回的结果类型;否则就为Null!

subjectModFunction返回的类型,由这个方法而决定!所以说在对应方法的闭包里最后表达式是什么类型,那这方法就是什么类型!这和之前讲解的let相似!

 T.let(block: (T) -> R): R {}

1.2.2 示例二

open class Human(val age: Int)

class Boy(val name: String, age: Int) : Human(age)
class Man(val name: String, age: Int) : Human(age)
class Dog(val weight: Int)

class MagicBox2<T : Human>(vararg item: T) {
    var available = true
    var subject = item
    fun fetch(index: Int): T? {
        return subject[index].takeIf { available }
    }

    fun <R> fetch(index: Int, subjectModFunction: (T) -> R): R? {
        return subjectModFunction(subject[index]).takeIf { available }
    }

    operator fun get(index: Int): T? = subject[index].takeIf { available }
}

fun main() {
    val box1 = MagicBox2(
        Boy("Jack", 15)
        , Man("Bob", 20),
        Human(12)
    )
    box1.fetch(2)?.run {
        println("your age is $age")
    }
    
    println("-----------------------")

    box1.fetch(0) {
        var it = it as Boy
        var man= Man(it.name, it.age.plus(3))
        "我已经成年了,我年龄为: ${man.age}"
    }.run(::println)

    println("-----------------------")

    box1[1]?.run { println("your age is $age") }
}

运行效果

your age is 12
-----------------------
我已经成年了,我年龄为: 18
-----------------------
your age is 20

其实这个示例重点关注class MagicBox2<T : Human>(vararg item: T)这里面的vararg关键字,它的意思有点像java里面的类型Human ...,意思就是在对应方法里,形参可以传多个进来。里面的subject自然而然变成了对应的数组类型。

2. 扩展

扩展?什么是扩展?

顾名思义,扩展,就是在对应对象上扩展自己想要的东西,然后可供自己使用。

这么神奇的么?来试试?连Java都没有这玩意!

2.1 属性扩展

//给 String 额外提供了 addExt 方法
fun String.addExt(amount: Int = 1) = this + "!".repeat(amount)
//给所有成员 都提供了 easyPrint 方法用来打印当前对象
fun <T> T.easyPrint() = println(this)

fun main{
    println("abc".addExt(10))
    123.easyPrint()
    //这里表示扩展后,依然能够正常使用Kotlin提供的API
    "abc".addExt(10).easyPrint().also { }.let { }
}

运行效果

abc!!!!!!!!!!
123
abc!!!!!!!!!!

是不是很好玩呢?系统核心的对象你都能在之上进行扩展!

既然能这样!那我是不是可以在对应对象里加入非空判断的扩展函数?

2.2 方法扩展

fun String?.printWithDefault(default: String) = println(this ?: default)

fun main{
    val nullableString: String? = null
    nullableString.printWithDefault("abc")
}

从这个代码上看,扩展函数的意思就是如果说,当前对象为null,那么就返回默认值!

那么问题来了,这样写,如果是Int类型的对象为null该怎么办呢?

于是乎带着问题重新新增了一个扩展!

fun String?.printWithDefault(default: String) = println(this ?: default)
fun Int?.printWithDefault(default: Int) = println(this ?: default)

fun main{
    val nullableString: String? = null
    nullableString.printWithDefault("abc")
    val nullableInt:Int?=null
    nullableInt.printWithDefault (12)
}

运行效果

abc
12

看到这运行效果,果然还真是按照这想法来的。但看着看着这样写还是有点java化。

想看看最终效果是咋样的。

infix fun String?.printWithDefault(default: String) = println(this ?: default)
infix fun Int?.printWithDefault(default: Int) = println(this ?: default)

fun main{
    val nullableString: String? = null
//    nullableString.printWithDefault("abc")
    nullableString printWithDefault "cba"
    val nullableInt:Int?=null
//    nullableInt .printWithDefault (12)
    nullableInt printWithDefault 13
}

运行效果

cba
13

注意看区别!在原有扩展前加入了infix关键字,然后在使用的时候,没有使用.方法()的方式了,而是用空格分隔就能调用对应的方法以及传入对应的参数。

那么现在问题来了!

  • 对应的扩展是针对当前类,还是全局类呢?
  • 相同对象在不同地方定义同一扩展会怎样?
  • 是否跟属性或者方法一样有对应的private/public等修饰符?

3.3 解疑问题

在这里插入图片描述

//集合扩展,调用该方法将会先把集合内里面的元素打乱,随后取第一个元素
fun <T> Iterable<T>.randomTake(): T = this.shuffled().first()

如图所示

在这里创建了一个新类,里面定义对应的扩展函数。意思就是将集合内里面的元素打乱,随后取第一个元素。进入另一个类,来看看使用体验:

fun main{
    val list = listOf("Jason", "Jack", "Tom")
    list.randomTake().run(::println)
}

居然发现能够正常使用,运行看下效果哇:

Jack

也就是说,默认的扩展是全局有效。现在验证下第二个问题!

fun <T> Iterable<T>.randomTake(): T = this.shuffled().first()

fun main() {
    val list = listOf("Jason", "Jack", "Tom")
    list.randomTake().run(::println)
}

当吧扩展复制粘贴到当前类的一瞬间,代码爆红了!很明显这种方式不行!

那阔不阔以通过特殊修饰符(private/public等)来实现相同对象在不同地方定义同一扩展呢?

进入Test.kt

//集合扩展,调用该方法将会先把集合内里面的元素打乱,随后取第一个元素
private fun <T> Iterable<T>.randomTake(): T = this.shuffled().first()

发现代码依旧报红!

进入KotlinStudy08.kt

private fun <T> Iterable<T>.randomTake(): T = this.first()

fun main{
    val list = listOf("Jason", "Jack", "Tom")
    list.randomTake().run(::println)
}

发现代码正常了,也就是说,自定义扩展默认全局,如果想要实现同一扩展在不同地方呈现不同效果的话,可以将对应相同的扩展都标注为private类型

结束语

好了,本篇到这也结束了!在本篇里相信你对Kotlin对应的泛型以及扩展有所了解!在下一篇里,将会重点讲解Kotlin里面的函数式编程!

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-11-15 15:59:21  更:2021-11-15 16:00:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:55:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码