-
接口定义
kotlin规定所有的接口属性和函数实现都要使用override关键字,接口中定义的函数不需要open关键字修饰,他们默认就是open的
interface Moveable{
//接口的定义,kotlin规定所有的接口属性和函数实现都要使用override关键字(也就是任何类实现该接口,必须实现里面的属性和函数实现),接口中定义的函数并不需要open关键字修饰,他们默认就是open的
//一般接口中不定义属性,只声明一些函数
val maxSpeed : Int
get() = (1..50).shuffled().last()
val wheels : Int
fun move(moveable: Moveable) : String
}
//接口的定义
class Car(val _name: Int, override val wheels: Int = 4) : Moveable{
override var maxSpeed: Int
get() = super.maxSpeed // 这里写法和java一样
set(value){}
override fun move(moveable: Moveable): String {
TODO("Not yet implemented")
}
}
-
抽象类
抽象类,abstract关键字,与java一样
//抽象类
abstract class Gun(val range : Int){
abstract fun shoot() : String
}
class AK47 : Gun(range = 100){
override fun shoot(): String {
return "ak47 shootting......"
}
}
-
定义泛型类,泛型函数,多泛型函数
demo:MagicBox类指定的泛型参数由放在<>里的字母T表示,T是个代表item类型的占位符。MagicBox类能接受任何类型的item作为主构造函数值(item:T),并将item值赋给同样是T类型的subject私有属性。
//定义泛型类
class MagicBox <T : Human> (item : T){
var available = false
private val subject : T = item
//泛型函数也可以用于参数
fun fetch() : T? {
//标准函数,当takeif的lambda结果是true,才会返回调用者。如果lambda结果是false,返回null
return subject.takeIf { available }
}
//多泛型参数(1个新需求,要求此函数将一个男孩变成男人)
//这个重载函数参数是一个匿名函数,匿名函数中的参数是一个T对象,返回的是一个R对象;当前函数返回的就是一个R对象
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 Dog(val weight : Int)
class Man(val name: String,val age: Int)'
fun main() {
//定义泛型类
val magicBoy : MagicBox<Boy> = MagicBox<Boy> (Boy("jack",20))
//如果定义了泛型类型约束,Dog没有继承Human,因此这里不能用了
// val magicDog = MagicBox<Dog> (Dog(10))
//泛型函数
magicBoy.available = true
magicBoy.fetch()?.run {
println("you find $name")
}
//多泛型参数
val man = magicBoy.fetch {
//返回一个man对象,加了10岁
Man(it.name, it.age.plus(10))
}
println(man?.age)
//泛型类型约束,类似与java的泛型类型约束
}
-
vararg关键字
需求:MagicBox2能存放任何类型的Human实例,但是一次只能放一个,如果需要放入多个实例呢?
定义泛型类,这里使用varagr修饰,则这个参数变为可变参数
package com.example.myapplication
/**
* varage关键字
* 需求:magicbox2能存放任何类型的human实例,但是一次只能放一个,如果需要放入多个实例呢
*/
//定义泛型类,这里使用varagr修饰,则这个参数变为可变参数
class MagicBox2 <T : Human> (vararg item : T){
var available = false
//这里先暂且记住要写out,不写out会报错
private val subject : Array<out T> = item
//泛型函数也可以用于参数
fun fetch(index : Int) : T? {
//标准函数,当takeif的lambda结果是true,才会返回调用者。如果lambda结果是false,返回null
return subject[index].takeIf { available }
}
//多泛型参数(1个新需求,要求此函数将一个男孩变成男人)
//这个重载函数参数是一个匿名函数,匿名函数中的参数是一个T对象,返回的是一个R对象;当前函数返回的就是一个R对象
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 Human2(val age: Int)
class Boy2(val name :String,age : Int) : Human(age)
class Dog2(val weight : Int)
class Man2(val name: String,val age: Int)
fun main() {
//因为用了varage修饰,这里传参可以传多个
val magicBoy : MagicBox2<Boy> = MagicBox2<Boy> (Boy("jack",20),Boy("jacky",30))
magicBoy.available = true
magicBoy.fetch(1)?.run {
println("you find $name")
}
val man = magicBoy.fetch(1) {
Man2(it.name,it.age+10)
}
println(man?.age)
//[]操作符重载,重载后可以这样调用
println(magicBoy[1])
}
-
out协变,in逆变
总结一句话就是:
out修饰后,子类泛型对象可以赋值给父类泛型对象;
in修饰后,父类泛型对象可以赋值给子类泛型对象
package com.example.myapplication
/**
* in 和 out的区别
*/
//out,协变,如果泛型类只将泛型类型作为函数的返回,那么使用out,可以称之为生产类/接口,因为它主要是生产(produce)指定的泛型对象
interface Production<out T>{
fun product() : T
}
//in,逆变,如果泛型类只将泛型类型作为函数的入参,那么使用in,可以称之为消费者类/接口,因为它主要是用来消费(consume)指定的泛型对象
interface Consumer<in T>{
fun consumer(item : T)
}
open class Food
open class FastFood : Food()
class Hamburger : FastFood()
//实体商店,生产food(爷爷)
class FoodStore : Production<Food>{
override fun product(): Food {
println("food is readey")
return Food()
}
}
//快餐商店,生产快餐(爸爸)
class FastFoodStore : Production<FastFood>{
override fun product(): FastFood {
println("fastfood is readey")
return FastFood()
}
}
//汉堡包商店,生产汉堡包(儿子)
class HamburgerStore : Production<Hamburger>{
override fun product(): Hamburger {
println("Hamburger is readey")
return Hamburger()
}
}
//----------------以上是生产者demo,out修饰--------------------------------------------
//----------------以下是消费者demo,in修饰---------------------------------------------
class EveryBody : Consumer<Food>{
override fun consumer(item: Food) {
println("任何人吃食物")
}
}
class ModernPeople : Consumer<FastFood>{
override fun consumer(item: FastFood) {
println("现代人吃快餐")
}
}
class American : Consumer<Hamburger>{
override fun consumer(item: Hamburger) {
println("美国人吃汉堡")
}
}
fun main() {
val food : Production<Food> = FoodStore()
//下面这两行如果Production没有out关键词修饰,下面是报错的。java中的泛型,左右两边的泛型必须是同一类型,不可以是继承关系的那种。
//但是在kotlin中,out修饰后,子类泛型对象可以赋值给父类泛型对象
val fastFood : Production<Food> = FastFoodStore()
val hamburger : Production<Food> = HamburgerStore()
hamburger.product()
//----------------以上是生产者demo,out修饰--------------------------------------------
//----------------以下是消费者demo,in修饰---------------------------------------------
val consumerHamburger : Consumer<Hamburger> = American()
//下面这两行如果Consumer没有in关键词修饰,下面是报错的。java中的泛型,左右两边的泛型必须是同一类型,不可以是继承关系的那种。
//但是在kotlin中,in修饰后,父类泛型对象可以赋值给子类泛型对象
val consumerFood : Consumer<Hamburger> = EveryBody()
val consumerFastFood : Consumer<Hamburger> = ModernPeople()
}
-
reified关键字
有时候,可能想知道某个泛型参数具体是什么类型,reified关键字能帮我们检查泛型参数类型
package com.example.myapplication
/**
* reified
* 有时候,可能想知道某个泛型参数具体是什么类型,reified关键字能帮我们检查泛型参数类型,
*/
fun main() {
val magicBox3 = MagicBox3()
val randomOrBackUp = magicBox3.getRandomOrBackUp {
Man3("Tom", 33)
}
println(randomOrBackUp)
}
class MagicBox3{
//这里需要使用reified关键字修饰T,否则下面的retrun里的random is T这一行会报错;
//添加了reified关键字修饰后,需要将该函数声明为inline内联函数
inline fun <reified T> getRandomOrBackUp(backup : () -> T) : T{
val items = listOf(
Boy3("jack",10),
Man3("John",30)
)
//随机获取到集合的一个对象
val random = items.shuffled().first()
println("random "+random)
//如果随机获取到的就是T类型,那么直接返回,否则返回backup函数的返回对象
//Important:这里可能会有疑问,T本身就是泛型,random is T根本看不懂,我理解的是这个T类型本身是什么类型取决与backup函数返回的类型,它返回什么类型,那么整个类里面所有的T泛型都是什么类型
//这里需要使用关键词reified,否则会报错
//因为在main方法中调用getRandomOrBackUp传入的匿名函数的返回值是Man3,所以这里的T指的就是Man3
return if (random is T){
random
}else{
backup()
}
}
}
open class Human3(val age: Int)
class Boy3(val name :String,age : Int) : Human3(age){
override fun toString(): String {
return "Boy3(name = $name,age = $age )"
}
}
class Man3(val name: String,age: Int) : Human3(age){
override fun toString(): String {
return "Man3(name = $name,age = $age )"
}
}
网友评论