协方差,不变性和逆变性用简单的英语解释? [英] Covariance, Invariance and Contravariance explained in plain English?

查看:108
本文介绍了协方差,不变性和逆变性用简单的英语解释?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天,我在Java中阅读了一些关于协方差,逆变(和不变性)的文章。我阅读了英文和德文维基百科的文章,以及IBM的一些其他博客文章和文章。

Today, I read some articles about Covariance, Contravariance (and Invariance) in Java. I read the English and German wikipedia article, and some other blog posts and articles from IBM.

但我对这些内容有何疑惑?有人说它是关于类型和子类型之间的关系,有些人说它是关于类型转换的,有些人说它用来决定方法是否被覆盖或超载。

But I'm still a little bit confused on what these exactly are about? Some say it's about relationship between types and subtypes, some says it's about type conversion and some says it's used to decide whether a method is overridden or overloaded.

所以我是用简单的英语寻找简单的解释,向初学者展示了协方差和逆变(和不变性)。加上一个简单的例子。

So I'm looking for an easy explanation in plain English, that shows a beginner what Covariance and Contravariance (and Invariance) is. Plus point for an easy example.

推荐答案


有人说它是关于类型和子类型之间的关系,另外说它是关于类型转换的,其他人说它用于决定方法是否被覆盖或超载。

Some say it is about relationship between types and subtypes, other say it is about type conversion and others say it is used to decide whether a method is overwritten or overloaded.

以上所有。

从本质上讲,这些术语描述了类型转换如何影响子类型关系。也就是说,如果 A B 是类型, f 是类型转换,≤子类型关系(即A≤B表示 A 是<$的子类型c $ c> B ),我们

At heart, these terms describe how the subtype relation is affected by type transformations. That is, if A and B are types, f is a type transformation, and ≤ the subtype relation (i.e. A ≤ B means that A is a subtype of B), we have


  • f A≤B暗示 f(A)≤f(B)
  • $,则c>是协变的b $ b
  • f 是逆变的,如果A≤B暗示 f(B )≤f(A)

  • f 如果以上都不存在则不变

  • f is covariant if A ≤ B implies that f(A) ≤ f(B)
  • f is contravariant if A ≤ B implies that f(B) ≤ f(A)
  • f is invariant if neither of the above holds

让我们考虑一个例子。设 f(A)= List< A> 其中 List

Let's consider an example. Let f(A) = List<A> where List is declared by

class List<T> { ... } 

f covariant ,逆变或不变? Covariant意味着 List< String> List< Object> 的子类型,反对a List< Object> List< String> 的子类型,并且不变为另一个的子类型,即 List< String> List< Object> 是不可转换的类型。在Java中,后者是真的,我们说(有点非正式地)泛型是不变的。

Is f covariant, contravariant, or invariant? Covariant would mean that a List<String> is a subtype of List<Object>, contravariant that a List<Object> is a subtype of List<String> and invariant that neither is a subtype of the other, i.e. List<String> and List<Object> are inconvertible types. In Java, the latter is true, we say (somewhat informally) that generics are invariant.

另一个例子。设 f(A)= A [] 。是 f 协变,逆变还是不变?也就是说,String []是Object []的子类型,Object []是String []的子类型,还是既不是另一个的子类型? (答案:在Java中,数组是协变的)

Another example. Let f(A) = A[]. Is f covariant, contravariant, or invariant? That is, is String[] a subtype of Object[], Object[] a subtype of String[], or is neither a subtype of the other? (Answer: In Java, arrays are covariant)

这仍然是相当抽象的。为了使它更具体,让我们看看Java中的哪些操作是根据子类型关系定义的。最简单的例子是赋值。声明

This was still rather abstract. To make it more concrete, let's look at which operations in Java are defined in terms of the subtype relation. The simplest example is assignment. The statement

x = y;

仅在 typeof(y)≤typeof(x)时编译。也就是说,我们刚刚了解到语句

will compile only if typeof(y) ≤ typeof(x). That is, we have just learned that the statements

ArrayList<String> strings = new ArrayList<Object>();
ArrayList<Object> objects = new ArrayList<String>();

不会用Java编译,但是

will not compile in Java, but

Object[] objects = new String[1];

将。

另一个例子子类型关系是一个方法调用表达式:

Another example where the subtype relation matters is a method invocation expression:

result = method(a);

非正式地说,通过赋值 a来评估此语句到方法的第一个参数,然后执行方法体,然后将方法返回值赋给 result 。与上一个示例中的普通赋值一样,右侧必须是左侧的子类型,即此语句只有在 typeof(a)≤typeof(参数(方法)) returntype(方法)≤typeof(结果)。也就是说,如果方法声明为:

Informally speaking, this statement is evaluated by assigning the value of a to the method's first parameter, then executing the body of the method, and then assigning the methods return value to result. Like the plain assignment in the last example, the "right hand side" must be a subtype of the "left hand side", i.e. this statement can only be valid if typeof(a) ≤ typeof(parameter(method)) and returntype(method) ≤ typeof(result). That is, if method is declared by:

Number[] method(ArrayList<Number> list) { ... }

以下表达式都不会编译:

none of the following expressions will compile:

Integer[] result = method(new ArrayList<Integer>());
Number[] result = method(new ArrayList<Integer>());
Object[] result = method(new ArrayList<Object>());

但是

Number[] result = method(new ArrayList<Number>());
Object[] result = method(new ArrayList<Number>());

将。

子类型的另一个例子事情是压倒一切的。考虑:

Another example where subtyping matters is overriding. Consider:

Super sup = new Sub();
Number n = sup.method(1);

其中

class Super {
    Number method(Number n) { ... }
}

class Sub extends Super {
    @Override 
    Number method(Number n);
}

非正式地,运行时会将其重写为:

Informally, the runtime will rewrite this to:

class Super {
    Number method(Number n) {
        if (this instanceof Sub) {
            return ((Sub) this).method(n);  // *
        } else {
            ... 
        }
    }
}

对于要编译的标记行,重写方法的方法参数必须是重写方法的方法参数的超类型,返回类型是重写方法的子类型。从形式上讲, f(A)= parametertype(方法asdeclaredin(A))必须至少是逆变的,如果 f(A)= returntype(方法asdeclaredin(A))必须至少是协变的。

For the marked line to compile, the method parameter of the overriding method must be a supertype of the method parameter of the overridden method, and the return type a subtype of the overridden method's one. Formally speaking, f(A) = parametertype(method asdeclaredin(A)) must at least be contravariant, and if f(A) = returntype(method asdeclaredin(A)) must at least be covariant.

注意上面的至少。这些是最低要求,任何合理的静态类型安全面向对象编程语言都会强制执行,但编程语言可能会选择更严格。对于Java 1.4,当重写方法时,参数类型和方法返回类型必须相同(类型擦除除外),即 parametertype(方法asdeclaredin(A))= parametertype(方法asdeclaredin(B)) 覆盖时。从Java 1.5开始,在覆盖时允许使用协变返回类型,即以下内容将在Java 1.5中编译,但不在Java 1.4中编译:

Note the "at least" above. Those are minimum requirements any reasonable statically type safe object oriented programming language will enforce, but a programming language may elect to be more strict. In the case of Java 1.4, parameter types and method return types must be identical (except for type erasure) when overriding methods, i.e. parametertype(method asdeclaredin(A)) = parametertype(method asdeclaredin(B)) when overriding. Since Java 1.5, covariant return types are permitted when overriding, i.e. the following will compile in Java 1.5, but not in Java 1.4:

class Collection {
    Iterator iterator() { ... }
}

class List extends Collection {
    @Override 
    ListIterator iterator() { ... }
}

我希望我涵盖了所有内容 - 或者更确切地说,划伤了表面。我仍然希望它有助于理解类型方差的抽象但重要的概念。

I hope I covered everything - or rather, scratched the surface. Still I hope it will help to understand the abstract, but important concept of type variance.

这篇关于协方差,不变性和逆变性用简单的英语解释?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆