- 定义泛型类
- 泛型函数
- 泛型类型约束
- vararg关键字与get函数
- out协变
- in逆变
- invariant不变
- reified
1.定义泛型类
泛型类的构造函数可以接受任意类型
泛型参数由放在一对<>里的字母T表示
class Magic <T>(item : T){
private var subject :T = item
}
class Boy(val name : String,val age : Int)
class Dog(val weight:Int)
fun main() {
val magic1 : Magic<Boy> = Magic(Boy("Jack", 18))
val magic2 : Magic<Dog> = Magic(Dog(20))
}
2.泛型函数
class Magic2 <T>(item : T){
var available = false
private var subject :T = item
fun fetch() : T?{
return subject.takeIf { available }
}
}
class Boy2(val name : String,val age : Int)
class Dog2(val weight:Int)
fun main() {
val magic1 : Magic2<Boy2> = Magic2(Boy2("Jack", 18))
magic1.apply {
available = true
}.fetch()?.run {
println("you find $name")
}
}
3.多泛型参数
class Magic3 <T>(item : T){
var available = false
private var subject :T = item
fun fetch() : T?{
return subject.takeIf { available }
}
//把一个Boy变成Man
//返回类型也是泛型
fun <R> fetch(subjectModFunction : (T) -> R) : R?{
return subjectModFunction(subject).takeIf { available }
}
}
class Boy3(val name : String, val age : Int)
class Man(val name : String, val age : Int)
fun main() {
val magic1 : Magic3<Boy3> = Magic3(Boy3("Jack", 18))
magic1.apply {
available = true
}.fetch {
Man(it.name,it.age.plus(20))
}?.run {
println("$name , $age")
}
}
3.泛型类型约束
class Magic4 <T : Human>(item : T){
var available = false
private var subject :T = item
fun fetch() : T?{
return subject.takeIf { available }
}
//把一个Boy变成Man
//返回类型也是泛型
fun <R> fetch(subjectModFunction : (T) -> R) : R?{
return subjectModFunction(subject).takeIf { available }
}
}
open class Human(val age : Int)
class Boy4(val name : String, age : Int) : Human(age)
class Man2(val name : String,age : Int) : Human(age)
fun main() {
val magic1 : Magic4<Boy4> = Magic4(Boy4("Jack", 18))
magic1.apply {
available = true
}.fetch {
Man2(it.name,it.age.plus(20))
}?.run {
println("$name , $age")
}
}
4.vararg关键字与get函数
传多个相同参数
class Magic5 <T : Human2>(vararg item : T){
var available = false
//out关键字 泛型数组
private var subject :Array<out T> = item
fun fetch(index : Int) : T?{
return subject[index].takeIf { available }
}
//把一个Boy变成Man
//返回类型也是泛型
fun <R> fetch(index : Int,subjectModFunction : (T) -> R) : R?{
return subjectModFunction(subject[index]).takeIf { available }
}
}
open class Human2(val age : Int)
class Boy5(val name : String, age : Int) : Human2(age)
class Man3(val name : String, age : Int) : Human2(age)
fun main() {
val magic1 : Magic5<Boy5> = Magic5(Boy5("Jack", 18),Boy5("Ross", 18))
magic1.apply {
available = true
}.fetch(1) {
Man3(it.name,it.age.plus(20))
}?.run {
println("$name , $age")
}
}
重载get运算符
operator fun get(index: Int): T?{
return subject[index].takeIf { available }
}
//就可以通过这样取值
magic1[1]
5.out协变
如果泛型类只将泛型类型作为函数的返回,那么使用out
可以称之位生产类、生产接口,因为它主要是用来生产指定的泛型对象
子类泛型对象可以赋值给父类泛型对象
6.in逆变
如果泛型类只将泛型类型作为函数的入参,那么使用In
可以称之为消费者类、消费者接口,因为它主要是用来消费指定的泛型对象
父类泛型对象可以赋值给子类泛型对象
7.invariant不变
如果泛型类即将泛型类型作为函数参数,又作为函数输出
那么即不使用In也不使用out
为什么使用in&out
提高函数的扩展性 -> 多态
out只返回泛型 -> 为了支持返回所有泛型 -> 所有子类可以赋值给父类
in只接收泛型 -> 为了支持接收所有泛型 -> 所有父类可以赋值给子类
interface Production<out T>{
fun product() : T
}
interface Comsumer<in T>{
fun consume(item : T)
}
interface ProductionConsuumer<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("FoodStore product")
return Food()
}
}
//快餐商店
class FastFoodStore : Production<FastFood>{
override fun product(): FastFood {
println("FastFoodStore product")
return FastFood()
}
}
//汉堡商店
class BurgerStore : Production<Burger>{
override fun product(): Burger {
println("BurgerStore product")
return Burger()
}
}
//消费者
class EveryBody : Comsumer<Food>{
override fun consume(item: Food) {
println("EveryBody consume(")
}
}
class ModernPeople : Comsumer<FastFood>{
override fun consume(item: FastFood) {
println("ModernPeople consume(")
}
}
class AmericanPeople : Comsumer<Burger>{
override fun consume(item: Burger) {
println("AmericanPeople consume(")
}
}
fun main() {
//赋值
val production1 : Production<Food> = FoodStore()
//java里不行 kotlin可以 -> 是因为有out关键字 -> 子类泛型对象可以赋值给父类泛型对象 ->实际上是子类对象
val production2 : Production<Food> = FastFoodStore()
production2.product()
println(production2 is Food) //false
println(production2 is FastFood) //false
println(production2 is FastFoodStore)//true
//父类泛型对象可以赋值给子类泛型对象 -> in关键字 -> 实际类型是父类对象
val consumer1 : Comsumer<Burger> = EveryBody()
val consumer2 : Comsumer<Burger> = ModernPeople()
val consumer3 : Comsumer<Burger> = AmericanPeople()
}
9.reified
有时候可能想知道某个泛型参数具体是什么类型,reified关键字可以帮助检查、
泛型参数的类型,Kotlin不允许对泛型参数做类型检查,因为泛型参数类型会被擦除
也就是说,T的类型信息在运行时是不可知的
class Magic5 <T : Human2>(){
// fun <T> randomOrBackup(backup: () -> T) : T{
// val items = listOf(
// Boy5("Jack",20),
// Man3("John",40)
// )
//
// val random = items.shuffled().first()
// //random is T 报错,在运行期间是不可知的
// return if(random is T){
// random
// }else{
// backup()
// }
// }
inline fun <reified T> randomOrBackup(backup: () -> T) : T{
val items = listOf(
Boy5("Jack",20),
Man3("John",40)
)
val random = items.shuffled().first()
//保留类型
return if(random is T){
random
}else{
backup()
}
}
}
open class Human2(val age : Int)
class Boy5(val name : String, age : Int) : Human2(age)
class Man3(val name : String, age : Int) : Human2(age)
fun main() {
val box1 : Magic5<Human2> = Magic5()
val subject = box1.randomOrBackup {
Man3("Jimmy",38)
}
}