https://www.bilibili.com/video/BV1wf4y1s7TG?p=95
generic
object目录下
对象相关 继承 类默认是封闭的,要让某个类开放继承,必须使用opem关键字修饰它
1 2 3 4 5 6 7 8 9 10 11 12 open class Product (val name:String) { fun description () = "Product: $name " open fun load () = "Nothing.." } class LuxuryProduct : Product ("Luxury" ){ override fun load () =" LuxuryProduct loading" } fun main () { val p : Product = LuxuryProduct() println(p.load()) }
类型检测 智能类型转换
1 2 3 4 5 6 7 8 println(p is Product) println(p is LuxuryProduct) println(p is File) if (p is LuxuryProduct){ println((p as LuxuryProduct).special()) println(p.special()) }
Kotlin层次 无须在代码里显示指定,每一个类都会继承一个共同的叫做Any的超类。
Object关键字 定义一个能产生一个实例的类- 单例
Object关键字有三种方式
对象声明
有利于组织代码和管理状态,尤其是管理整个应用运行生命周期内的某些一致性状态
对象表达式
1 2 3 4 5 6 7 8 9 10 11 open class Player { open fun load () = "loading nothing.." } fun main () { val p = object : Player(){ override fun load () = "anonymous nothing.." } println(p.load()) }
伴生对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class ConfigMap { companion object { private const val PATH = "xxxx" fun load () = File(PATH).readBytes() } } fun main () { ConfigMap.load() }
类相关 嵌套类
在Java中,当你在另一个类中声明一个类时,它会默认变成内部类 。而在Kotlin中,没有显式修饰符的嵌套类与Java中的static嵌套类是一样的。要把它变成一个内部类来持有一个外部类的引用的话需要使用inner修饰符。
嵌套类和内部类在Java与Kotlin中的对应关系
类A在另一个类B中声明
在Java中
在Kotlin中
嵌套类(不存储外部类的引用)
static class A
class A
内部类(存储外部类的引用)
class A
inner class A
https://blog.csdn.net/weixin_41953808/article/details/112450204
https://juejin.cn/post/6844903910084182030
1 2 3 4 5 6 7 8 9 10 11 12 class InnerClassTest { class Equipment (var name:String){ fun show () = println("equipment:$name " ) } fun battle () { } } fun main () { InnerClassTest.Equipment("shap knife" ).show() }
在Kotlin中引用外部类 实例的语法,需要使用this@Outer从Inner类去访问Outer类:
1 2 3 4 5 class Outer { inner class Inner { fun getOuterReference () :Outer = this @Outer } }
数据类
数据类使用条件
1 2 3 4 5 6 7 8 data class Coordinate (var x:Int ,var y:Int ) { val isInBounds = x > 0 && y > 0 } fun main () { println(Coordinate(10 ,20 )) println(Coordinate(10 ,20 )==Coordinate(10 ,20 )) }
结果
Coordinate(x=10, y=20) // 说明默认提供了toString方法
重写了equals方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public boolean equals (@Nullable Object var1) { if (this != var1) { if (var1 instanceof Coordinate) { Coordinate var2 = (Coordinate)var1; if (this .x == var2.x && this .y == var2.y) { return true ; } } return false ; } else { return true ; } } }
Copy
注意:次构造函数数据不会copy过来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 data class Student ( var name: String, val age: Int ){ private val hobby = "music" val subject:String var score = 0 init { println("initializing student" ) subject = "english" } constructor (_name: String):this (_name,10 ){ score = 10 ; } override fun toString () : String { return "Student(name='$name ', age=$age , hobby='$hobby ', subject='$subject ', score=$score )" } } fun main () { val s = Student("Jon" ) val copy = s.copy("girl" ) var s2 = s.copy(name = "girl2" , age = 18 ) println(s) println(s2) println(copy) }
解构声明
普通类
1 2 3 4 5 6 7 8 9 class PlayerScore (val experience:Int ,val level:Int ) { operator fun component1 () = experience operator fun component2 () = level } fun main () { val (x,y) = PlayerScore(10 , 20 ) println("$x , $y " ) }
Data数据类
数据类自动生成解构语法
1 2 3 4 5 6 7 8 9 10 11 data class Coordinate (var x:Int ,var y:Int ) { val isInBounds = x > 0 && y > 0 } fun main () { println(Coordinate(10 ,20 )) println(Coordinate(10 ,20 )==Coordinate(10 ,20 )) val (x,y) = Coordinate(10 ,20 ) println("$x , $y " ) }
运算符重载 如果要将内置运算符应用在自定义类身上,你必须重写运算符函数,告诉编译器该如何操作自定义类
1 2 3 4 5 6 7 8 9 10 11 data class Coordinate2 (var x:Int ,var y:Int ) { val isInBounds = x > 0 && y > 0 operator fun plus (other:Coordinate2 ) = Coordinate2(x + other.x,y+other.y) } fun main () { val c1=Coordinate2(10 , 20 ) val c2=Coordinate2(10 , 20 ) println(c1 + c2) }
枚举类 用来定义常量集合特殊的类
枚举类是一个实例
1 2 3 4 5 6 7 8 9 10 11 enum class Direction { EAST, WEST, SOUTH, NORTH } fun main () { println(Direction.EAST) println(Direction.EAST is Direction) }
枚举类定义函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 enum class Direction2 (private val coordinate: Coordinate) { EAST(Coordinate(1 , 0 )), WEST(Coordinate(-1 , 0 )), SOUTH(Coordinate(-1 , 0 )), NORTH(Coordinate(1 , 0 )); fun updateCoordinate (playerCoordinate: Coordinate ) = Coordinate(playerCoordinate.x + coordinate.x, playerCoordinate.y + coordinate.y) } fun main () { println(Direction2.EAST.updateCoordinate(Coordinate(10 , 20 ))) }
代数数据类型 可以用来表示一组子类型的闭集,枚举类就是一种简单的ADT
密封类
class Qualified(val licenseId:String):LicenseStatus2() 保存数据,如果用emum类 会很麻烦
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 sealed class LicenseStatus2 { object UnQualified:LicenseStatus2() object Learning:LicenseStatus2() class Qualified (val licenseId:String):LicenseStatus2() } class Driver2 (var status: LicenseStatus2){ fun checkLicense () :String{ return when (status){ is LicenseStatus2.UnQualified -> "没资格" is LicenseStatus2.Learning -> "在学" is LicenseStatus2.Qualified -> "有资格,驾驶证编号: ${((this.status as LicenseStatus2.Qualified).licenseId)} " } } } fun main () { val status1 = LicenseStatus2.Learning val status = LicenseStatus2.Qualified("2333003" ) val driver = Driver2(status) println(driver.checkLicense()) }
接口
InterfaceTest.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 interface Movable { var maxSpeed:Int var wheels:Int fun move (movable:Movable ) :String } class Car (_name:String,override var wheels:Int =4 ):Movable{ override var maxSpeed: Int get () = TODO("Not yet implemented" ) set (value) {} override fun move (movable: Movable ) : String { TODO("Not yet implemented" ) } }
默认实现 可以在接口里提供默认属性getter方法和函数实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 interface Movable { 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 (value) {} override fun move (movable: Movable ) : String { TODO("Not yet implemented" ) } }
抽象类
1 2 3 4 5 6 7 8 9 10 11 12 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 { TODO() } }
泛型 定义泛型类
magicBox1.kt
1 2 3 4 5 6 7 8 9 10 class MagicBox <T > (item:T){ protected var subject:T = item } class Boy (val name:String,val age:Int )class Dog (val weight:Int )fun main () { val box1 = MagicBox(Boy("John" , 20 )) val box2 = MagicBox(Dog( 20 )) }
泛型函数
泛型参数也可以用于函数。
定义一个函数用于获取元素,当且仅当MagicBox可用时,才能获取元素。
magicBox2.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class MagicBox <T > (item: T) { var available = false protected var subject: T = item fun fetch () : T? { return subject.takeIf { available } } } class Boy (val name: String, val age: Int )class Dog (val weight: Int )fun main () { val box1 = MagicBox(Boy("John" , 20 )) val box2 = MagicBox(Dog(20 )) box1.available = true box1.fetch()?.run { println("you find $name " ) } }
多泛型参数 magicBox3.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class MagicBox <T > (item: T) { var available = false protected var subject: T = item fun fetch () : T? { return subject.takeIf { available } } fun <R> fetch (subjectModFunction: (T ) -> R ) : R? { return subjectModFunction(subject).takeIf { available } } } class Boy (val name: String, val age: Int )class Man (val name: String, val age: Int )class Dog (val weight: Int )fun main () { val box1 = MagicBox(Boy("John" , 20 )) val box2 = MagicBox(Dog(20 )) box1.available = true box1.fetch()?.run { println("you find $name " ) } val fetch = box1.fetch { Man(it.name, it.age.plus(15 )) } }
泛型类型约束 确保MagicBox只能装指定类型的物品, 如Human类型,咋弄?
magicBox4.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class MagicBox4 <T:Human > (item: T) { var available = false protected var subject: T = item fun fetch () : T? { return subject.takeIf { available } } fun <R> fetch (subjectModFunction: (T ) -> R ) : R? { return subjectModFunction(subject).takeIf { available } } } 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 )fun main () { val box1 = MagicBox4(Boy("John" , 20 )) box1.available = true box1.fetch()?.run { println("you find $name " ) } val fetch = box1.fetch { Man(it.name, it.age.plus(15 )) } }
vararg关键字与get函数 MagicBox能存放任何类型的Human实例,但一次只能放一个,如果要存放多个实例呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class MagicBox <T : Human > (vararg item: T) { var available = false protected var subject: Array<out T> = 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 } } } 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 )fun main () { val box1 = MagicBox(Boy("John" , 20 ), Boy("Jack" , 20 ), Boy("Jon" , 20 )) box1.available = true box1.fetch(1 )?.run { println("you find $name " ) } val fetch = box1.fetch(2 ) { Man(it.name, it.age.plus(15 )) } }
[]操作符 运算符重载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class MagicBox <T : Human > (vararg item: T) { var available = false protected var subject: Array<out T> = 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 } } 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 )fun main () { val box1 = MagicBox(Boy("John" , 20 ), Boy("Jack" , 20 ), Boy("Jon" , 20 )) box1.available = true box1.fetch(1 )?.run { println("you find $name " ) } val fetch = box1.fetch(2 ) { Man(it.name, it.age.plus(15 )) } box1[0 ] }
invariant 不变 如果泛型类即将泛型类型作为函数参数,又将泛型类型作为函数的输出,那么即不用out也不用in.
1 2 3 4 interface ProductionConsumer <T > { fun product () : T fun consume (item: T ) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 interface Production <out T > { fun product () : T } interface Consumer <in T > { fun consume (item: T ) } interface ProductionConsumer <T > { fun product () : T fun consume (item: T ) } open class Food open class FastFood :Food ()open 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 FastFood" ) return FastFood() } } class BurgerFoodStore : Production <Burger > { override fun product () : Burger { println("Product Burger" ) return Burger() } } 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 AmericanPeople : Consumer <Burger > { override fun consume (item: Burger ) { println("Eat Burger" ) } }
Out生产 1 2 3 interface Production <out T > { fun product () : T }
子类泛型对象可以赋值给父类泛型对象 如 下面production2
java. T extends Food 等于kotlin T : Food
泛型有继承关系,可以直接赋值,java做不到,只能强转
ArrayList list = new ArrayList(); // java里面这种写法报错
java只有 ? super Food 和 ? extends Food , 没有对泛型T , in out这种操作
1 2 3 4 5 6 fun main () { val production1 : Production<Food> = FoodStore() val production2 : Production<Food> = FastFoodStore() }
为什么需要 out
如果泛型有继承关系,可以直接赋值, Java只能用具体类
1 2 3 4 5 6 public class GenericTypeTest { public static void main (String[] args) { } }
In 输入
1 2 3 4 interface Consumer <in T > { fun consume (item: T ) }
父类泛型对象可以赋值给子类泛型对象 , 用in
1 2 3 4 5 6 7 8 9 10 fun main () { val consumer1:Consumer<Burger> = EveryBody() val consumer2:Consumer<Burger> = ModernPeople() consumer2.consume(Burger()) val consumer3:Consumer<Burger> = AmericanPeople() }
Reified
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class MagicBox <T : Human > () { inline fun <reified T> randomOrBackup (backup: () -> T ) : T { val items = listOf(Boy("jocnk" , 20 ), Man("john" , 20 )) val random = items.shuffled().first() println(random) return if (random is T) { random } else { backup() } } } fun main () { val box1: MagicBox<Man> = MagicBox() val subject = box1.randomOrBackup { Man("Jimmy" , 28 ) } println(subject) } open class Human (val age: Int )class Boy (val name: String, age: Int ) : Human(age){ override fun toString () : String { return "Boy(name='$name ')" } } class Man (val name: String, age: Int ) : Human(age){ override fun toString () : String { return "Man(name='$name ')" } }