博主前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住也分享一下给大家
👉点击跳转到教程
一、Kotlin中接口的定义
- Kotlin中接口定义
Kotlin规定所有的接口属性和函数实现都要使用override关键字,接口中
定义的函数并不需要open关键字修饰,它们默认就是open的。
/**
* Kotlin中接口定义
* Kotlin规定所有的接口属性和函数实现都要使用override关键字,接口中
* 定义的函数并不需要open关键字修饰,它们默认就是open的。
*/
interface Movable {
/**
* 默认实现
* 只要你愿意,你可以在接口里提供默认属性的getter方法和函数实现。
*/
val maxSpeed: Int
get() = (1..500).shuffled().last()
var wheels: Int
fun move(movable: Movable): String
}
class Car(_name: String, override var wheels: Int = 4) : Movable {
override var maxSpeed: Int
get() = super.maxSpeed
set(max) {
}
override fun move(movable: Movable): String {
println("数据一下")
return "数据一下"
}
}
二、抽象类
/**
* 抽象类
* 要定义一个抽象类,你需要在定义之前加上abstract关键字,除了具体的函数实现,
* 抽象类也可以包含抽象函数(只有定义,没有函数实现)
*/
abstract class Gun(val range: Int) {
abstract fun pullTrigger(): String
protected fun doSomething() {
println("doSomething")
}
}
class AK47(val price: Int) : Gun(range = 500) {
override fun pullTrigger(): String {
return "ce"
}
}
三、泛型详解
/**
* 定义泛型类
* 泛型类的构造函数可以接受任何类型。
* MagicBox类指定的泛型参数由放在一对<>里的字母T表示,T是个代表item类型的占位图。
* MagicBox类接受任何类型的item作为主构造函数值(item:T),并将item赋值给同样是T类型的
* subject私有属性
*
* 泛型参数通常用字母T(代表type)表示,当然,想用其他字母,甚至是英文单词都是可以的。
* 不过,其他支持泛型的语言都在用这个约定俗称的T,所以建议你继续用它,这样写出的代码别人更容易理解。
*
* 泛型类型约束
* 如果要确保MagicBox里面只能装指定类型的物品,如Human类型,或其子类 这样定义<H : Human>
*/
class MagicBox<T : Human>(vararg item: T) {
var available = false
private var subject: Array<out T> = item
/**
* 泛型函数
* 泛型参数也可用于函数
* 定义一个函数用于获取元素,当且仅当MagicBox可用时,才能获取元素。
*/
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
}
}
}
open class Human(val age: Int)
class Boy(val name: String, age: Int) : Human(age)
class Dog(val weight: Int)
class Man(val name: String, age: Int) : Human(age)
fun main() {
val magicBox = MagicBox(
Boy("jack", 15),
Boy("Jacky", 16),
Boy("John", 26)
)
magicBox.available = true
magicBox.fetch(1)?.run {
println("you find $name")
}
val man = magicBox.fetch(2) {
Man(it.name, it.age + 10)
}
}
输出结果如下
you find Jacky
四、out协变和in逆变详解
/**
* out 协变,如果泛型类只将泛型类型作为函数的返回(输出),那么使用out
* 可以称之为生产类/接口,因为它主要用来生产(produce)指定的泛型对象。
*
* 子类泛型对象可以赋值给父类泛型对象,用out
*/
interface Production<out T> {
fun product(): T
}
/**
* in 逆变
*in(逆变),如果泛型类只将泛型类型作为函数的入参(输入),那么使用in,可以称之为消费者类/接口,
* 因为它主要用来消费(consumer)指定的泛型对象
*
* 父类泛型对象可以赋值给子类泛型对象,用in
*
*/
interface Consumer<in T> {
fun consumer(item: T)
}
/**
* invariant(不变)
* 如果泛型类既将泛型类型作为函数参数,又将泛型类型作为函数的输出,那么既不用out也不用in
*/
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 product(): Food {
println("Product food.")
return Food()
}
}
/**
* 快餐商店
*/
class FastFoodStore : Production<FastFood> {
override fun product(): FastFood {
println("Product food.")
return FastFood()
}
}
/**
* 汉堡商店
*/
class BurgerStore : Production<Burger> {
override fun product(): Burger {
println("Product food.")
return Burger()
}
}
fun main() {
//赋值
val production1: Production<Food> = FoodStore()
val production2: Production<Food> = FastFoodStore()
}
五、reified关键字
/**
* @Author: ly
* @Date: 2023/2/1
* @Description:
*/
class MagicBox<T : Human> {
/**
* 随机产生一个对象,如果不是指定类型的对象,
* 就通过backup函数生成一个指定类型的对象
*/
// fun <T> randomOrBackup(backup: () -> T): T {
// val items = listOf(
// Boy("Jack", 20),
// Man("John", 35)
// )
// var random = items.shuffled().first()
// return if (random is T) {
// random
// } else {
// backup()
// }
// }
/**
* reified关键字
* 有时候,你可能想知道某个泛型参数具体是什么类型,reified关键字能够帮你
* 检查泛型参数类型。Kotlin不允许对泛型类型T做类型检查,因为泛型参数类型会被类型擦除
* 也就是说,T的类型信息在运行时是不可知的,Java也有这样的规则。
* */
inline fun <reified T> randomOrBackup(backup: () -> T): T {
val items = listOf(
Boy("Jack", 20),
Man("John", 35)
)
val random = items.shuffled().first()
return if (random is T) {
println(random)
random
} else {
backup()
}
}
}
open class Human(val age: Int)
class Boy(val name: String, age: Int) : Human(age) {
override fun toString(): String {
return "Boy(name='$name',age=$age)"
}
}
class Man(val name: String, age: Int) : Human(age) {
override fun toString(): String {
return "Man(name='$name',age=$age)"
}
}
fun main() {
val box1: MagicBox<Boy> = MagicBox()
//由backup函数,推断出来T的类型
val subject = box1.randomOrBackup {
Boy("Jack", 19)
}
println(subject)
}
输出结果
Boy(name='Jack',age=19)
另外一种可能输出的结果
Boy(name='Jack',age=20)
Boy(name='Jack',age=20)