class Channel<T : Message> {
fun send(t: T)
fun receive(): T
}
class Apple : Message()
class AppleChannel : Channel<Apple>() {
...
}
val appleChannel = AppleChannel()
val outMessageChannel: Channel<out Message> = appleChannel // MUST WORK
val messageChannel: Channel<Message> = outMessageChannel
// you say this should work, but...
messageChannel.send(Orange())
// sending orange on a channel that only knows how to send apples!
// Error!
3条答案
按热度按时间x3naxklr1#
不,这就是证据。
在这种情况下,唯一一致的做法是不允许将
Channel<out Message>
转换为Channel<Message>
。如果它被定义为
Channel<out T: Message>
,那么这将是安全的,但是尝试定义send
将导致错误。tzcvj98z2#
不,将
out Message
转换为Message
是不安全的。Channel<out Message>
基本上意味着Channel
被限制为只能生成Message
项,它不能使用它们,例如,因为我们不知道它到底可以使用什么类型。通过将它强制转换为Channel<Message>
,我们允许使用Message
。编译器无法在编译时或运行时验证这是否正确,因此它生成一个未检查的强制转换警告。如果
Channel
类型在你的例子中只用于生成元素,那么它应该在声明位置标记为out T
,然后我们可以简单地使用它。rkkpypqq3#
让我补充一下前面的答案,你的问题有两个层次。
“unchecked cast”警告不是关于你试图转换的类型,而是关于
Channel<X>
和Channel<Y>
在运行时没有区别的事实,因为type erasure。所以从一个类型到另一个类型的转换在运行时永远不会失败,即使它是错误的:它在运行时没有被检查(因此是“unchecked”),这可能会导致一些细微的错误,因为你是polluting the heap。这在强制转换非泛型类型(如
Any
到String
)或泛型类型的原始部分(如List<*>
到MutableList<*>
)时是不同的。如果所讨论的示例不是正确的类型,这些类型在运行时会失败。既然
Channel<out Message>
只能包含Message类型的对象或Message
类型的子类,那么这种类型转换不应该总是安全的吗?实际上不,正如其他答案所示,这是不安全的。声明中的
out
防止您将元素发送到该通道(它是out
-only,您不能将内容放入in
)。这防止您插入通道不支持的内容。强制转换将使编译器允许这样做,这在运行时是不正确的。