Generics 区别于*&引用;及;任何;在Kotlin泛型中

Generics 区别于*&引用;及;任何;在Kotlin泛型中,generics,kotlin,Generics,Kotlin,我不确定我是否完全理解SomeGeneric和SomeGeneric之间的区别。我认为*代表任何东西(通配符),而Any代表所有对象继承的对象。所以看起来它们应该是一样的,但是它们是吗?在我想你暗示的上下文中,SomeGeneric等同于SomeGeneric。Java的等价物是SomeGeneric,把它看作是一种不仅表示任何类型,而且表示您不知道确切是什么的固定类型的方法可能会有所帮助 例如,类型MutableList表示某事物的列表(您不知道具体是什么)。因此,如果你试图在这个列表中添加一

我不确定我是否完全理解
SomeGeneric
SomeGeneric
之间的区别。我认为
*
代表任何东西(通配符),而
Any
代表所有对象继承的对象。所以看起来它们应该是一样的,但是它们是吗?

在我想你暗示的上下文中,
SomeGeneric
等同于
SomeGeneric
。Java的等价物是
SomeGeneric,把它看作是一种不仅表示任何类型,而且表示您不知道确切是什么的固定类型的方法可能会有所帮助

例如,类型
MutableList
表示某事物的列表(您不知道具体是什么)。因此,如果你试图在这个列表中添加一些内容,你将不会成功。它可以是
String
s的列表,也可以是
Int
s的列表,或者是其他内容的列表。编译器根本不允许在此列表中放置任何对象,因为它无法验证列表是否接受此类型的对象。但是,如果您试图从这样的列表中获取一个元素,那么肯定会得到类型为
Any?
的对象,因为Kotlin中的所有对象都继承自
Any

以下评论:

另外,
List
可以包含任何类型的对象,但仅限于 类型,因此它可以包含字符串(但只能包含字符串),而
List
可以在同一列表中包含字符串、整数等


理解恒星投影(
*
)的关键是首先正确理解另外两种类型的投影
in
out
。之后,恒星投影就不言自明了


理解问题 假设您有一个通用类
板条箱
,用于储存水果。此类在
T
中是不变的。这意味着,这个类既可以消费也可以生产
T
(水果)。换句话说,这个类的函数将
T
作为参数(consume)并返回
T
(product)。
size()
函数是T独立的,它既不接受
T
,也不返回
T

class Crate<T> {
    private val items = mutableListOf<T>()
    fun produce(): T = items.last()
    fun consume(item: T) = items.add(item)
    fun size(): Int = items.size
}
fun useAsProducer(producer: Crate<out Fruit>) {

    // T is known to be out Fruit, so produces Fruit and its subtypes.
    val fruit = producer.produce()           // OK

    // Fruit is guaranteed. Can use functions and properties of Fruit.
    fruit.getColor()                         // OK
    
    // Consumer not allowed because you don't want to accidentally add
    // oranges, if this is a Crate<Apple>
    producer.consume(Orange())               // Error             
}
fun useAsConsumer(consumer: Crate<in Orange>) {

    // Produces Any?, no guarantee of Orange because this could
    // be a Crate<Fruit> with apples in it.
    val anyNullable = consumer.produce()     // Not useful
    
    // Not safe to call functions of Orange on the produced items.
    anyNullable.getVitaminC()                // Error

    // T is known to be in Orange, so consumes Orange and its subtypes.
    consumer.consume(MandarinOrange())       // OK
}

in
projection是
T
通过将
板条箱
投影为
中的
,您告诉编译器:“当我意外地将
板条箱
类用作
T
的生产者时,请给我一个错误,因为我只想安全地将该类用作
T
的消费者”:


Any
不是投影 当您说
板条箱
时,您不是在投影,您只是在使用原始不变类
板条箱
,它可以产生和消耗
任何

fun useAsAny(any: Crate<Any>) {

    // T is known to be Any. So, an invariant produces Any.
    val anyNonNull = any.produce()           // OK

    // T is known to be Any. So, an invariant consumes Any.
    any.consume(Fruit())                     // OK

    // Can use the T-independent functions and properties, of course.
    any.size()                               // OK
}
使用网站

class ProducerCrate<out T : Fruit> {
    private val fruits = listOf<T>()
    fun produce() : T = fruits.last()
}
fun useProducer(star: ProducerCrate<*>) {

    // Even though we project * here, it is known to be at least a Fruit
    // because it's an upper bound at the declaration-site.
    val fruit = star.produce()               // OK

    // Fruit is guaranteed. Can use functions and properties of Fruit.
    fruit.getColor()                         // OK
}
class ConsumerCrate<in T> {
    private val items = mutableListOf<T>()
    fun consume(item: T) = items.add(item)
    fun size(): Int = items.size
}
fun useConsumer(consumer: ConsumerCrate<*>) {

    // Cannot consume anything, because the lower bound is not supported
    // in Kotlin and T is unknown
    consumer.consume(Orange())               // Error

    // Only useful for T-independent functions and properties.
    consumer.size()                          // OK
}
class ProducerConsumerCrate<T : Fruit> {
    private val fruits = mutableListOf<T>()
    fun produce(): T = fruits.last()
    fun consume(fruit: T) = fruits.add(fruit)
}
fun useProducerConsumer(producerConsumer: ProducerConsumerCrate<*>) {

    // Even though we project * here, T is known to be at least a Fruit
    // because it's the upper bound at the declaration-site.
    val fruit = producerConsumer.produce()   // OK

    // Fruit is guaranteed. Can use functions and properties of Fruit.
    fruit.getColor()                         // OK

    // Consumer not allowed because you don't want to accidentally add
    // oranges, if this crate is a Crate<Apple>.
    producerConsumer.consume(Fruit())        // Error
}
使用网站

class ProducerCrate<out T : Fruit> {
    private val fruits = listOf<T>()
    fun produce() : T = fruits.last()
}
fun useProducer(star: ProducerCrate<*>) {

    // Even though we project * here, it is known to be at least a Fruit
    // because it's an upper bound at the declaration-site.
    val fruit = star.produce()               // OK

    // Fruit is guaranteed. Can use functions and properties of Fruit.
    fruit.getColor()                         // OK
}
class ConsumerCrate<in T> {
    private val items = mutableListOf<T>()
    fun consume(item: T) = items.add(item)
    fun size(): Int = items.size
}
fun useConsumer(consumer: ConsumerCrate<*>) {

    // Cannot consume anything, because the lower bound is not supported
    // in Kotlin and T is unknown
    consumer.consume(Orange())               // Error

    // Only useful for T-independent functions and properties.
    consumer.size()                          // OK
}
class ProducerConsumerCrate<T : Fruit> {
    private val fruits = mutableListOf<T>()
    fun produce(): T = fruits.last()
    fun consume(fruit: T) = fruits.add(fruit)
}
fun useProducerConsumer(producerConsumer: ProducerConsumerCrate<*>) {

    // Even though we project * here, T is known to be at least a Fruit
    // because it's the upper bound at the declaration-site.
    val fruit = producerConsumer.produce()   // OK

    // Fruit is guaranteed. Can use functions and properties of Fruit.
    fruit.getColor()                         // OK

    // Consumer not allowed because you don't want to accidentally add
    // oranges, if this crate is a Crate<Apple>.
    producerConsumer.consume(Fruit())        // Error
}
fun useProducerConsumer(producerConsumer:ProducerConsumerRate){
//即使我们在这里预测,T至少是一种水果
//因为这是申报地点的上限。
val fruit=producerConsumer.product()//确定
//水果是有保证的。可以利用水果的功能和特性。
fruit.getColor()//好的
//不允许使用消费者,因为您不想意外添加
//橙子,如果这个箱子是个箱子的话。
producerConsumer.consumer(水果())//错误
}

结论 不变量
板条箱的类型投影

投影 生产 消耗 行为
板条箱
水果
水果
生产者和消费者
板条箱
水果
Nothing
仅生产商
板条箱
Any?
水果
仅限消费者
板条箱
Any?
Nothing
没有生产者也没有消费者
回答不错,对于一些人来说,添加列表可能会有帮助,列表可以包含任何类型的对象,但只能包含该类型的对象,因此它可以包含字符串(但只能包含字符串),而列表可以包含字符串、整数等等,这是一篇有趣的文章,有着相似的解释:@fweigl我认为这样区分是不对的<代码>列表
也可以包含混合类型。这里:
val list:list=listOf(42,“Bob”)
。您只是不知道什么是
*
,而且
*
很可能是您喜欢的任何父类型,包括
any
本身(如我的示例中所示)。唯一重要的区别是,对于逆变或不变类型,如
MutableList
,在使用
*
时,禁止使用操作中的“
”,因为您无法静态地知道类型参数是什么,所以编译器无法做出任何假设。@Joffrey是的,您完全正确。奇怪的是,有人花了5年才注意到这一点!难以置信的回答!谢谢你的来信!