Kotlin入门学习记录
2023/12/04 - 2023/12/06
接口
接口默认为open
修饰,即为可以继承的,代码实现如下
interface Moveable {
var maxSpeed:Int
var wheels:Int
fun move(moveable: Moveable):String
}
class Car(_name:String,override var wheels:Int = 4):Moveable{
override var maxSpeed: Int
get() = TODO("Not yet implemented")
set(value) {}
override fun move(moveable: Moveable): String {
TODO("Not yet implemented")
}
}
接口的默认实现
可在接口中的属性提供默认的 getter 方法实现,代码实现如下
interface Moveable {
val maxSpeed:Int
get() = (0..9).shuffled().first()
var wheels:Int
fun move(moveable: Moveable):String
}
class Car(_name:String,override var wheels:Int = 4):Moveable{
override fun move(moveable: Moveable): String {
TODO("Not yet implemented")
}
}
fun main() {
println(Car("LY_C").maxSpeed)
}
抽象类
abstract
关键字,除了具体的函数实现,抽象类也可以包含抽象函数
泛型
泛型系统允许函数和其他类型接受你或编译器当前无法预知的类型
泛型类
泛型类的构造函数可以接受任何类型,<>
用于声明一个泛类,<>
中可以使用任何字母,不过泛型参数通常用字母T表示,代码实现如下
class MagicBox<T>(item:T){
private var subject = item
}
class Boy(val name:String,val age:Int)
class Dog(val weight:Int)
fun main() {
val magicBox:MagicBox<Boy> = MagicBox(Boy("LY_C", 21))
val magicBox1:MagicBox<Dog> = MagicBox(Dog(20))
}
泛型参数
泛型参数也可以用于函数,代码实现如下
/*
将Boy对象赋值给MagicBox中的subject属性
fetch()函数中使用了 takeIf内置函数
判断available为false时返回null
为true时返回subject本身即Boy对象
*/
class MagicBox<T>(item:T){
var available = false
private var subject = item
fun fetch():T?{
return subject.takeIf { available }
}
}
class Boy(val name:String,val age:Int)
fun main() {
val magicBox = MagicBox(Boy("LY_C", 21))
magicBox.available = true
magicBox.fetch()?.run {
println("you find $name")//you find LY_C
}
}
多泛型参数
泛型函数或泛型类也可以有多个泛型参数,代码实现如下
新 fetch 函数多了一个泛型参数 R。R 是英文单词 return 的缩写形式,表示这个泛型参数将用作 fetch 函数的返回类型
class MagicBox<T>(item:T){
var available = false
/*将对象赋值给MagicBox中的subject属性*/
private var subject = item
fun fetch():T?{
return subject.takeIf { available }
}
/*定义了一个用于返回的<R>
参数为 subjectModFunction:(T) -> R 函数*/
fun <R> fetch(subjectModFunction:(T) -> R):R?{
/*传递subject参数给subjectModFunction*/
return subjectModFunction(subject).takeIf { available }
}
}
class Boy(val name:String,val age:Int)
class Man(val name:String,val age:Int)
fun main() {
val magicBox = MagicBox(Boy("LY_C", 11))
magicBox.available = true
val man = magicBox.fetch(){
/*相当于subjectModFunction的函数体
接收subject 返回Man对象赋值给<R>*/
Man(it.name, it.age.plus(10))
}
man?.let { println("${it.name},${it.age}") }
}
泛型类型约束
如果只想传递一个类型的泛型,需要在声明泛型的时候给泛型指定类型,代码实现如下
class MagicBox<T:Human>(item:T){
var available = false
var subject = item
fun fetch():T?{
return subject.takeIf { available }
}
}
class Boy(val name:String,val age:Int):Human()
open class Human()
fun main() {
var box = MagicBox(Boy("LY_C", 21))
}
vararg关键字和get运算符函数
使用vararg
关键字,能接受多个值参,代码实现如下
注意
可变泛型参数赋值时必须加上out
class MagicBox<T:Human>(vararg item:T){
...
fun <R> fetch(index: Int,subjectModFunction:(T) -> R) : R? {
return subjectModFunction(subject[index]).takeIf { available }
}
}
class Boy(val name:String,val age:Int):Human()
class Gril(val name:String,val age:Int):Human()
open class Human()
fun main() {
val box = MagicBox(Boy("LY_C", 21),Boy("Test", 21))
box.available = true
box.fetch(1)?.run {
println("you find $name")
//you find Test
}
box.fetch(0)?.run {
println("you find $name")
//you find LY_C
}
val fetch = box.fetch(1) {
Gril("CRY", 21)
}
fetch?.let { println("${it.name},${it.age}") }
//CRY,21
}
使用get
运算符实现替代第一个fetch
函数,代码实现如下
class MagicBox<T:Human>(vararg item:T){
...
operator fun get(index: Int):T? = subject[index].takeIf { available }
...
}
...
fun main() {
val box = MagicBox(Boy("LY_C", 21),Boy("Test", 21))
box.available = true
box[1]?.run {
println("you find $name")
//you find Test
}
box[0]?.run {
println("you find $name")
//you find LY_C
}
}
in、out 逆变、协变
为进一步定制泛型参数,Kotlin 提供了 in
和 out
两个关键字
子类泛型对象可以赋值给父类用<out >
如果泛型类只将泛型进行返回输出,那么使用out
,代码实现如下
interface Production<out T>{
fun production():T
}
open class Food
open class FastFood:Food()
class Burger:FastFood()
class FoodShore:Production<Food>{
override fun production(): Food {
println("Production food")
return Food()
}
}
class FastFoodShore:Production<FastFood>{
override fun production(): FastFood {
println("Production food")
return FastFood()
}
}
fun main() {
//子类 Burger、FastFood 泛型对象可以
//赋值给父类 Food 用<out >
val production:Production<Food> = FoodShore()
val production2:Production<Food> = FastFoodShore()
val production3:Production<Food> = BurgerShore()
}
父类泛型对象可以赋值给子类用<in >
如果泛型类只将泛型作为参数传入,那么使用in
,代码实现如下
...
class Everybody:Consumer<Food>{
override fun consume(item: Food) {
println("Eat food")
}
}
class ModernPeople:Consumer<FastFood>{
override fun consume(item: FastFood) {
println("Eat FastFood")
}
}
class American:Consumer<Burger>{
override fun consume(item: Burger) {
println("Eat Burger")
}
}
fun main() {
...
//父类 Food 、FastFood 泛型对象可以
//赋值给子类 Burger 用<out >
val everybody:Consumer<Burger> = Everybody()
val everybody2:Consumer<Burger> = ModernPeople()
val everybody3:Consumer<Burger> = American()
}
invariant 不变
如果泛型类即将泛型作为参数传入又将泛型类作为输出,那么即不使用out
又不使用in
reified 关键字
想知道某个泛型参数具体是什么类型。reified 关键字能帮你检查泛型参数类型,代码实现如下
class MagicBox<T:Human>(){
//randomBackup函数参数写 backup 函数头
inline fun <reified T> randomBackup(backup:() -> T):T?{
val item = listOf(
Boy("test1",21),
Boy("test2",21)
)
val random:Human = item.shuffled().first()
// is 使用了多态 Boy继承了Human
// 如果 randomBackup传入的lambda是Boy或者Human
// 则返回item列表中随机元素
// 否则返回 randomBackup中的lambda值
return if (random is T){
random
}else{
backup()
}
}
}
class Boy(
override val name:String,
override val age:Int
):Human(name, age)
class Gril(val name:String,val age:Int)
class Man(
override val name:String,
override val age:Int
):Human(name, age)
open class Human(
open val name:String, open val age:Int)
fun main() {
var box:MagicBox<Man> = MagicBox()
val subject = box.randomBackup {
// 传入lambda
Man("LY_C",21)
Gril("CRY",21)
Human("LY_C",21)
}
println(subject?.name)
}