当前位置: 首页 > article >正文

【Android】Kotlin教程(6)

文章目录

      • 1.接口
      • 2.抽象类
      • 3.泛型类
      • 4.泛型函数
      • 5.多泛型参数
      • 6.out和int
      • 7.reified
      • 8.定义扩展函数
      • 9.扩展属性
      • 10.泛型扩展函数

1.接口

Kotlin 的接口可以既包含抽象方法的声明也包含实现。与抽象类不同的是,接口无法保存状态。它可以有属性但必须声明为抽象或提供访问器实现。

interface MyInterface {
    fun bar()
    fun foo() {
      // 可选的方法体
    }
}
interface Moveable {
    var maxSpeed: Int
    var wheels: Int

    fun move(moveable: Moveable): String
}

class Car(
    private val name: String,
    override var wheels: Int = 4,
    override var maxSpeed: Int = 100
) : Moveable {

    override fun move(moveable: Moveable): String {
        return "${moveable.javaClass.simpleName} with name $name is moving"
    }

    override fun toString(): String {
        return "Car(name=$name, wheels=$wheels, maxSpeed=$maxSpeed)"
    }
}

fun main() {
    val car = Car("xiaomi")
    println(car.move(car))
}

2.抽象类

抽象类是一种不能被实例化的类,它主要用于定义一组通用的行为和属性,这些行为和属性可以被其子类继承。抽象类可以包含抽象方法(没有实现的方法)以及具体的实现方法。子类必须提供抽象方法的具体实现,除非子类本身也是抽象的。

// 定义一个抽象类
abstract class Animals {
    // 抽象属性
    abstract val image: String

    // 抽象方法
    abstract fun makeSound()

    // 具体方法
    open fun breathe() {
        println("呼吸")
    }

    // 构造函数
    constructor(name: String) {
        println("动物的名字是 $name")
    }
}

// 实现抽象类
class Dog : Animals("狗") {
    override val image = "dog.jpg"

    override fun makeSound() {
        println("汪汪!")
    }
}

class Cat : Animals("猫") {
    override val image = "cat.jpg"

    override fun makeSound() {
        println("喵喵!")
    }
}

fun main() {
    val dog = Dog()
    dog.makeSound()  // 输出: 汪汪!
    dog.breathe()    // 输出: 呼吸

    val cat = Cat()
    cat.makeSound()  // 输出: 喵喵!
    cat.breathe()    // 输出: 呼吸
}

3.泛型类

泛型类的构造函数可以接受任何类型。

class MagicBox<T>(val item: T) {
    private var subject : T = item

    fun open() : String {
        return "subject -- $subject."
    }
}


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

class Tiger(val weight: Int)



fun main() {
    val  box1:MagicBox<Boy> = MagicBox(Boy("tony",10))
    val  box2:MagicBox<Tiger> = MagicBox(Tiger(100))
    println(box1.open()) // subject -- Boy@27716f4.
    println(box2.open()) // subject -- Boy@27716f4.
}

4.泛型函数

泛型参数也可以用于函数

class MagicBox<T>(val item: T) {
    private var subject : T = item

    fun open() : String {
        return "subject -- $subject."
    }

    fun call() : T {
        return subject
    }
}


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

class Tiger(val weight: Int)



fun main() {
    val  box1:MagicBox<Boy> = MagicBox(Boy("tony",10))
    val  box2:MagicBox<Tiger> = MagicBox(Tiger(100))
    println(box1.open()) // subject -- Boy@27716f4.
    println(box2.open()) // subject -- Boy@27716f4.
    println(box1.call()) // Boy@27716f4
    println(box2.call()) // Tiger@8efb846
}

5.多泛型参数

泛型函数或泛型类也可以有多个泛型参数。

定义多泛型参数的类

class Pair<T, U> (val first: T, val second: U) {
    fun printPair() {
        println("First: $first, Second: $second")
    }
}

fun main() {
    val pair = Pair(1, "one")
    pair.printPair()  // 输出: First: 1, Second: one
}

定义多泛型参数的接口

interface Container<K, V> {
    fun put(key: K, value: V)
    fun get(key: K): V?
}

class HashMapContainer<K, V> : Container<K, V> {
    private val map = mutableMapOf<K, V>()

    override fun put(key: K, value: V) {
        map[key] = value
    }

    override fun get(key: K): V? {
        return map[key]
    }
}

fun main() {
    val container: Container<String, Int> = HashMapContainer()
    container.put("key1", 100)
    println(container.get("key1"))  // 输出: 100
}

多泛型参数的函数

fun <T, U> combine(first: T, second: U): Pair<T, U> {
    return Pair(first, second)
}

fun main() {
    val result = combine(42, "answer")
    println(result)  // 输出: Pair(first=42, second=answer)
}

泛型约束:你可能希望对泛型参数进行一些限制,例如要求它们必须实现某个特定的接口。这可以通过类型约束来实现:

fun <T : Comparable<T>> findMax(a: T, b: T): T {
    return if (a > b) a else b
}

fun main() {
    val maxInt = findMax(3, 5)
    println(maxInt)  // 输出: 5

    val maxString = findMax("apple", "banana")
    println(maxString)  // 输出: banana
}

在这个例子中,findMax 函数的类型参数 T 被限制为实现了 Comparable 接口的类型,这样就可以使用比较运算符。

6.out和int

out关键字用于实现协变(covariance),这允许你在泛型类型参数上定义一种更灵活的类型关系。协变主要用于处理只读操作,比如从集合中获取元素,而不涉及写入或修改这些元素的操作。

协变是指当一个类型 A 是类型 B 的子类型时,那么 List<A> 也可以被视为List<B>的子类型。这种关系使得我们可以使用更通用的类型来引用具体的子类型实例。

逆变是指当一个类型 A 是类型 B 的子类型时,那么 Consumer<A> 也可以被视为 Consumer<B> 的子类型。这种关系使得我们可以使用更通用的类型来引用具体的子类型实例,但方向是相反的。

  • 父类泛型对象可以赋值给子类泛型对象,用in
  • 子类泛型对象可以赋值给父类泛型对象,用out
// out
interface Production<out T>{
    fun produce() : T
}

// in
interface Consumer<in T>{
    fun consume(t : T)
}

// 不变
interface ProductionConsumer<T> {
    fun product() : T
    fun consume(item : T)
}


open class Food


open class FastFood : Food()

class Burger : FastFood()

// 生产者
// 食品商店
class FoodStore : Production<Food>{
    override fun produce(): Food{
        println("Produce Food.")
        return Food()
    }
}

class FastFoodStore : Production<FastFood>{
    override fun produce(): FastFood{
        println("Produce FastFood.")
        return FastFood()
    }
}

class BurgerStore : Production<Burger>{
    override fun produce(): Burger{
        println("Produce Burger.")
        return Burger()
    }
}

class FoodConsumer : Consumer<Food>{
    override fun consume(item: Food) {
        println("Consume Food.")
    }
}

class FastFoodConsumer : Consumer<FastFood>{
    override fun consume(item: FastFood) {
        println("Consume FastFood.")
    }
}

class BurgerConsumer : Consumer<Burger>{
    override fun consume(item: Burger) {
        println("Consume Burger.")
    }
}
fun main() {
     val production1 : Production<Food> = FoodStore()
     val production2 : Production<Food> = FastFoodStore()
     val production3 : Production<Food> = BurgerStore()

    val consumer1 : Consumer<Food> = FoodConsumer()
    val consumer2 : Consumer<FastFood> = FoodConsumer()
    val consumer3 : Consumer<Burger> = FoodConsumer()
}

7.reified

reified 是一个关键字,用于使类型参数在运行时具体化。通常情况下,泛型的类型信息在编译后会被擦除(即类型擦除),这意味着你不能在运行时获取到具体的类型信息。然而,通过使用 reified 关键字,Kotlin 允许你在某些上下文中保留这些类型信息。

// 定义一个泛型类 MagicBox2,泛型 T 必须是 Human 的子类
class MagicBox2<T : Human> {

    // 定义一个内联泛型方法 randomOrBackup,使用 reified 关键字使 T 类型在运行时可用
    inline fun <reified T> randomOrBackup(backup: () -> T): T {
        // 创建一个包含不同类型 Human 对象的列表
        val items = listOf(
            Man("C++", 40),
            Feman("Kotlin", 45)
        )

        // 随机打乱列表并取第一个元素
        val randomItem = items.shuffled().first()

        // 如果随机选中的元素是 T 类型,则返回该元素;否则调用备份函数返回一个默认值
        return if (randomItem is T) {
            randomItem
        } else {
            backup()
        }
    }
}

// 定义一个开放类 Human,包含一个年龄属性
open class Human(val age: Int)

// 定义一个 Man 类,继承自 Human,包含一个姓名属性
class Man(val name: String, age: Int) : Human(age)

// 定义一个 Feman 类,继承自 Human,包含一个姓名属性
class Feman(val name: String, age: Int) : Human(age)

fun main() {
    // 创建一个 MagicBox2 实例,指定泛型为 Man
    val magicBox = MagicBox2<Man>()

    // 调用 randomOrBackup 方法,如果随机选中的不是 Man 类型,则返回一个 Feman 对象作为备份
    val man = magicBox.randomOrBackup {
        Feman("Java", 35)
    }

    // 打印结果,输出选中的对象的姓名
    println(man.name)
}

8.定义扩展函数

扩展函数允许你为现有的类添加新的功能,而无需修改该类的源代码。这使得你可以向库中的类或第三方库中的类添加自定义方法,从而增强其功能。扩展函数在使用时看起来就像它们是原始类的一部分一样。

定义扩展函数:要定义一个扩展函数,你需要在函数名前面指定接收者类型(即你要扩展的类),并在接收者类型和函数名之间使用点号 .。接收者类型的实例将作为隐式的第一个参数传递给扩展函数。

String 类添加一个扩展函数来检查字符串是否是回文:

fun String.isPalindrome(): Boolean {
    return this == this.reversed()
}


fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // “this”对应该列表
    this[index1] = this[index2]
    this[index2] = tmp
}


fun main() {
    val str = "madam"
    println(str.isPalindrome())  // 输出: true

    val list = mutableListOf(1, 2)
    list.swap(0, 1)
    println(list)  // 输出: [2, 1]
}

9.扩展属性

除了扩展函数,Kotlin 还支持扩展属性。扩展属性与扩展函数类似,但用于定义新的属性。

// 示例
val String.firstChar: Char?
    get() = if (this.isEmpty()) null else this[0]

fun main() {
    val str = "hello"
    println(str.firstChar)  // 输出: h
}

10.泛型扩展函数

class Box<T>(val item: T)

// 为 Box<T> 添加一个扩展函数
fun <T> Box<T>.printItem() {
    println("The item in the box is: $item")
}

fun main() {
    val intBox = Box(42)
    intBox.printItem()  // 输出: The item in the box is: 42

    val stringBox = Box("Hello, World!")
    stringBox.printItem()  // 输出: The item in the box is: Hello, World!
}

http://www.kler.cn/news/367855.html

相关文章:

  • 挑战Java面试题复习第2天,百折不挠
  • vue面试题+wx-open-launch-app开放标签唤醒app方法
  • Android 12.0进程保活白名单功能实现
  • 2024年CentOS镜像下载地址,包括CentOS官网、国内镜像下载,超详细也
  • esp32学习:语音识别教程esp-skainet库的使用
  • 【计算机操作系统】课程 作业二 进程与线程 408考研
  • 算法设计与分析:贪心算法思想的应用
  • Redisson(三)应用场景及demo
  • HTML+CSS实现超酷超炫的3D立方体相册
  • Spring-SpringMVC-SpringBoot理解
  • Java基础-JVM
  • 【宝塔面板】轻松使用docker搭建lobe-chat项目(AI对话)
  • js纯操作dom版购物车(实现购物车功能)
  • Cannot read property ‘prototype’ of undefined 表单
  • 云资源管理与优化:提升效率的技术指南
  • 【数据集】NCEP辐射数据-用于计算漫射天窗比(diffuse skylight ration)
  • ELK之路第二步——可视化界面Kibana
  • Hadoop:yarn的Rust API接口
  • 面向对象思想和面向过程思想分析
  • 【LeetCode】每日一题 2024_10_27 冗余连接(并查集)
  • JavaWeb的小结08
  • 前端聊天室页面开发(赛博朋克科技风,内含源码)
  • Axure随机验证码高级交互
  • 血量更新逻辑的实现
  • Windows AD 域的深度解析 第一篇:AD 域原理与多系统联动
  • 考研要求掌握的C语言程度(堆排序)1