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年才注意到这一点!难以置信的回答!谢谢你的来信!