参考:
类型上边界:Any? 类型下边界:Nothing 关于星号投射,其实就是*代指了所有类型,相当于out Any? : 不能生产,只能消费星号投射
有些时候, 你可能想表示你并不知道类型参数的任何信息, 但是仍然希望能够安全地使用它. 这里所谓"安全地使用"是指, 对泛型类型定义一个类型投射, 要求这个泛型类型的所有的实体实例, 都是这个投射的子类型。
对于这个问题, Kotlin 提供了一种语法, 称为 星号投射(star-projection):
假如类型定义为 Foo , 其中 T 是一个协变的类型参数, 上界(upper bound)为 TUpper ,Foo<> 等价于 Foo . 它表示, 当 T 未知时, 你可以安全地从 Foo<> 中 读取TUpper 类型的值.
假如类型定义为 Foo , 其中 T 是一个反向协变的类型参数, Foo<> 等价于 Foo . 它表示, 当 T 未知时, 你不能安全地向 Foo<> 写入 任何东西.
假如类型定义为 Foo , 其中 T 是一个协变的类型参数, 上界(upper bound)为 TUpper , 对于读取值的场合, Foo<*> 等价于 Foo , 对于写入值的场合, 等价于 Foo .
如果一个泛型类型中存在多个类型参数, 那么每个类型参数都可以单独的投射.
比如, 如果类型定义为interface Function<in T, out U> , 那么可以出现以下几种星号投射:
Function<*, String> , 代表 Function<in Nothing, String> ;
Function<Int, *> , 代表 Function<Int, out Any?> ;
Function<, > , 代表 Function<in Nothing, out Any?> .
注意: 星号投射与 Java 的原生类型(raw type)非常类似, 但可以安全使用
关于星号投射,其实就是*代指了所有类型,相当于Any?
class A<T>(val t: T, val t2: T, val t3: T)
class Apple(var name: String)
fun main() {
//使用类
val a1: A<*> = A(12, "String", Apple("苹果"))
val a2: A<Any?> = A(12, "String", Apple("苹果")) //和a1是一样的
println("=========================================")
val apple = a1.t3 //参数类型为Any
println(apple)
println("=========================================")
val apple2 = apple as Apple //强转成Apple类
println(apple2.name)
println("=========================================")
//使用数组
val list1: ArrayList<*> = arrayListOf("String", 1, 1.2f, Apple("苹果"))
// list1.add(true)
for (item in list1) {
println(item)
}
println("===========* 等价于 out Any? 只能消费,不能生产 =================")
val list2: ArrayList<out Any?> = arrayListOf("String", 1, 1.2f, Apple("苹果"))
// list2.add(true)
for (item in list2) {
println(item)
}
println("=========================================")
val list3: ArrayList<Any?> = arrayListOf("String", 1, 1.2f, Apple("苹果"))
list3.add(false)
for (item in list3) {
println(item)
}
println("=========================================")
}
星号投影,用来表示不知道关于泛型实参的任何信息,跟Java的?问号通配符类似;
注意
MutableList<*> 和 MutableList<Any?> 不一样;
MutableList<T> 在T上是不变型的,
MutableList<Any?>包含的是任何类型的元素;
MutableList<*>是包含某种特定类型元素,但不知是哪个类型,所以不能写入;但可读取;
编译器将MutableList<*> 当做out投影的类型 MutableList<out Any?>,不能让她消费任何东西;
PECS 代表生产者-Extens,消费者-Super(Producer-Extends, Consumer-Super)。
泛型类与泛型方法对比
定义:
//定义一个【泛型类】,并定义如下两个方法
internal class TestPrint1<T> {
fun show(t: T) {
println(t)
}
fun print(t: T) {
println(t)
}
}
//定义一个类,并定义如下两个【泛型方法】
//泛型方法更具有扩展性。
//泛型方法可以让不同方法操作不同类型,且类型还不确定。
//与泛型类不同,泛型方法的类型参数只能在它锁修饰的泛型方法中使用。
internal class TestPrint2 {
fun <T> show(t: T) {
println(t)
}
fun <T> print(t: T) {
println(t)
}
fun <U, T> sum(u: U, t: T) {
println(u.toString() + " version is " + t)
}
}
测试
//测试 : 泛型类
@Test
fun test8() {
val testPrint11 = TestPrint1<Int>()
testPrint11.print(1)
testPrint11.show(10)
val testPrint12 = TestPrint1<String>()
testPrint12.print("2")
testPrint12.print("box")
}
//测试 : 泛型方法
@Test
fun test9() {
val testPrint2 = TestPrint2()
testPrint2.print(1)
testPrint2.print("2")
testPrint2.print(false)
testPrint2.show(10)
testPrint2.show("15")
testPrint2.show(true)
testPrint2.sum(1, false)
testPrint2.sum(true, "b")
}
对比发现:泛型方法比泛型类更具有扩展性。
泛型方法测试
@Test
fun test7() {
printMsg(1, "2", false, mutableListOf(0, 1))
}
private fun <T> printMsg(vararg args: T) {
for (t in args) {
println("t is $t")
}
}
泛型接口
定义
//定义泛型接口
internal interface ShowInterface<T> {
fun show(t: T)
}
//实现类确定了类型
/**
* 传入泛型实参时:
* 定义一个生产器实现这个接口,虽然我们只创建了一个泛型接口Generator<T>
* 但是我们可以为T传入无数个实参,形成无数种类型的Generator接口。
* 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型
* 即:Generator<T>,public T next();中的的T都要替换成传入的String类型。
*/
internal class ShowClass1 : ShowInterface<String> {
override fun show(t: String) {
println("show:$t")
}
}
//实现类类型不确定
/**
* 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
* 即:class FruitGenerator<T> implements Generator<T>{
* 如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class"
*/
internal class ShowClass2<T> : ShowInterface<T> {
override fun show(t: T) {
println("show:$t")
}
}
测试
@Test
fun test10() {
//确定了类型
val showClass1 = ShowClass1()
showClass1.show("1")//这里只能string
//不确定类型,动态设置
val showClass21 = ShowClass2<String>()
showClass21.show("666")
val showClass22 = ShowClass2<Int>()
showClass22.show(999)
}
无界类型通配符
kotlin : * 等价于 Java : ?
@Test
fun test1() {
val a1 = ArrayList<String>()
a1.add("a")
a1.add("b")
a1.add("c")
val a2 = ArrayList<Int>()
a2.add(1)
a2.add(2)
a2.add(3)
// printList1(a1) //报错
// printList1(a2) //报错
printList1(a1.toMutableList())
printList1(a2.toMutableList())
println("=========================")
printList2(a1)
printList2(a2)
println("=========================")
printList3(a1)
printList3(a2)
}
//Any
private fun printList1(list: MutableList<Any>) {
val iterator = list.iterator()
while (iterator.hasNext()) {
println(iterator.next())
}
}
//泛型方法
private fun <T> printList2(list: MutableList<T>) {
val iterator = list.iterator()
while (iterator.hasNext()) {
println(iterator.next())
}
}
//占位符,也称为通配符。
// kotlin * 表示元素类型可以匹配任意类型(java中为?)
//"*","?"可以接收任何类型。
//类型通配符我感觉上和泛型方法差不多,只是不用在使用前进行定义
private fun printList3(list: ArrayList<*>) {
val iterator = list.iterator()
while (iterator.hasNext()) {
println(iterator.next())
}
}
示例:
//定义一个Person类
open class Person(var name: String)
// 定义一个Student 并继承 Person ( name 来自person )
class Student(name: String) : Person(name)
private val personList: MutableList<Person> = mutableListOf(
Person("pA"),
Person("pB"),
Person("pC")
)
private val studentList: MutableList<Student> = mutableListOf(
Student("s1"),
Student("s2"),
Student("s3")
)
class TestC {
@Test
fun test12() {
println("=================0")
// printMethod0(personList)
printMethod0(studentList)
println("=================1")
printMethod1(personList)
// printMethod1(studentList)
println("=================2")
printMethod2(personList)
printMethod2(studentList)
println("=================3")
printMethod3(personList)
printMethod3(studentList)
println("=================4")
printMethod4(personList)
printMethod4(studentList)
println("=================5")
printMethod5(personList)
printMethod5(studentList)
println("=================6")
printMethod6(personList.toMutableList())
printMethod6(studentList.toMutableList())
}
//只能打印Student
private fun printMethod0(list: MutableList<Student>) {
val iterator = list.iterator()
while (iterator.hasNext()) {
when (val next = iterator.next()) {
//先判断子类,在判断父类(因为子类也属于父类)
is Student -> print("s=${next.name} ")
is Person -> print("p=${next.name} ")
}
}
println()
}
//只能打印person
private fun printMethod1(list: MutableList<Person>) {
val iterator = list.iterator()
while (iterator.hasNext()) {
when (val next = iterator.next()) {
is Student -> print("s=${next.name} ")
is Person -> print("p=${next.name} ")
}
}
println()
}
//kotlin 中 out
//我们称? extends T 为 泛型上限定: 可以接收T和T的子类
private fun printMethod2(list: MutableList<out Person>) {
val iterator = list.iterator()
while (iterator.hasNext()) {
when (val next = iterator.next()) {
is Student -> print("s=${next.name} ")
is Person -> print("p=${next.name} ")
}
}
println()
}
//kotlin 中 in
//我们称? super T 为 泛型下限定: 可以接收T和T的父类
private fun printMethod3(list: MutableList<in Student>) {
val iterator = list.iterator()
while (iterator.hasNext()) {
when (val next = iterator.next()) {
is Student -> print("s=${next.name} ")
is Person -> print("p=${next.name} ")
}
}
println()
}
//泛型<T : Person> 表示 <? extend Person> : Person及其子类
private fun <T : Person> printMethod4(list: MutableList<T>) {
val iterator = list.iterator()
while (iterator.hasNext()) {
when (val next = iterator.next()) {
is Student -> print("s=${next.name} ")
is Person -> print("p=${next.name} ")
}
}
println()
}
//通配符
private fun printMethod5(list: MutableList<*>) {
val iterator = list.iterator()
while (iterator.hasNext()) {
when (val next = iterator.next()) {
is Student -> print("s=${next.name} ")
is Person -> print("p=${next.name} ")
}
}
println()
}
//Any
private fun printMethod6(list: MutableList<Any>) {
val iterator = list.iterator()
while (iterator.hasNext()) {
when (val next = iterator.next()) {
is Student -> print("s=${next.name} ")
is Person -> print("p=${next.name} ")
}
}
println()
}
}