我刚刚在我的编程语言课程中学到了“逆变参数类型实际上是安全的,但它们并没有被发现有用,因此在实用语言中不受支持。”虽然它们不受支持,但我很困惑为什么我们这样的例子在理论上仍然是“安全的”:
class Animal {
...
public bool compare(Panda) { ... }
}
class Panda extends Animal {
...
public bool compare(Animal) { ... }
}
根据我的理解,当完成可能导致特异性丧失的事情时,会出现子类型的问题。那么如果我这样做呢? :
Panda p = new Panda();
Animal a = new Animal
...
p.compare(a);
当我看到这一点时,似乎熊猫可能(并且可能确实)有一些额外的领域,普通动物不会知道。因此,即使他们所有的动物特定数据成员相同,熊猫也可以拥有其他不同的东西。如何将它与普通动物进行比较呢?它会仅仅考虑动物的东西而忽略其余的东西吗?
答案 0 :(得分:2)
在您的示例中,您不使用任何generic类型。您Panda
延长了Animal
,这是inheritance的示例,并且导致polymorphism或多或少的描述。检查链接。
要获得逆转,您需要考虑一些通用类型。我将使用.NET类型IComparer`1[T]
作为示例。使用C#语法(我将使用而不是Java),我们在IComparer
中通过在定义中编写T
来表明in
是逆变:
public interface IComparer<in T>
{
...
}
假设我有一个返回IComparer`1[Animal]
(或IComaparer<Animal>
)的方法,例如:
static IComparer<Animal> CreateAnimalComparer()
{
// code that returns something here
}
现在在C#中,说:
是合法的IComparer<Panda> myPandaComparer = CreateAnimalComparer();
现在,这个是因为逆转。请注意,类型IComparer<Animal>
并非来自(或“扩展”)类型IComparer<Panda>
。相反,Panda
派生自Animal
,这导致IComparer<Xxxx>
可以相互指派(以相反的顺序,因此“逆转”(不是“协方差”))。
声明一个Comparer<>
逆变器有意义的原因是,如果你有一个可以比较两个任意动物的比较器,并返回一个表示哪个更大的有符号数,那么同一个比较器也可以接受两个大熊猫并比较那些。因为大熊猫是动物。
所以关系
任何
Panda
都是Animal
(来自继承)导致关系
任何
IComparer<Animal>
都是IComparer<Panda>
(通过逆转)。
对于协方差的示例,具有相同的关系
任何
Panda
都是Animal
导致
任何
IEnumerable<Panda>
都是IEnumerable<Animal>
通过协方差(IEnumerable<out T>
)。