0

我刚刚在我的编程语言课上了解到“逆变参数类型实际上是安全的,但尚未发现它们有用,因此在实际语言中不受支持。” 即使它们不受支持,我也很困惑为什么我们给出的这个例子在理论上仍然是“安全的”:

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); 

当我看到这个时,似乎熊猫可以(并且可能确实)有一些普通动物不会知道的额外字段。因此,即使它们所有特定于动物的数据成员都相同,熊猫也可以有其他不同的东西。将它与普通动物进行比较怎么会好呢?它会只考虑动物专用的东西而忽略其余的吗?

4

1 回答 1

2

在您的示例中,您不使用任何泛型类型。你有Pandaextends Animal,它是继承的一个例子,并导致多态性,这或多或少是你所描述的。检查链接。

要获得逆变,您需要考虑一些泛型类型。我将使用 .NET 类型IComparer`1[T]作为示例。使用 C# 语法(我将使用它而不是 Java),我们通过在定义中编写来表明它IComparer逆变的:Tin

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>)。

于 2012-11-25T13:00:52.233 回答