举例说明在 Java 中重载和覆盖的情况下协变和逆变的函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2501023/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 08:31:13  来源:igfitidea点击:

Give examples of functions which demonstrate covariance and contravariance in the cases of both overloading and overriding in Java?

javacovariancecontravariance

提问by JavaUser

Please show a good example for covariance and contravariance in Java.

请举例说明 Java 中的协变和逆变。

采纳答案by Hardcoded

Covariance:

协方差:

class Super {
  Object getSomething(){}
}
class Sub extends Super {
  String getSomething() {}
}

Sub#getSomething is covariant because it returns a subclass of the return type of Super#getSomething (but fullfills the contract of Super.getSomething())

Sub#getSomething 是协变的,因为它返回 Super#getSomething 的返回类型的子类(但满足 Super.getSomething() 的约定)

Contravariance

逆变

class Super{
  void doSomething(String parameter)
}
class Sub extends Super{
  void doSomething(Object parameter)
}

Sub#doSomething is contravariant because it takes a parameter of a superclass of the parameter of Super#doSomething (but, again, fullfills the contract of Super#doSomething)

Sub#doSomething 是逆变的,因为它采用 Super#doSomething 参数的超类的参数(但是,同样,满足 Super#doSomething 的契约)

Notice: this example doesn't work in Java. The Java compiler would overload and not override the doSomething()-Method. Other languages do support this style of contravariance.

注意:这个例子在 Java 中不起作用。Java 编译器将重载而不覆盖 doSomething() 方法。其他语言确实支持这种逆变风格。

Generics

泛型

This is also possible for Generics:

这对于泛型也是可能的:

List<String> aList...
List<? extends Object> covariantList = aList;
List<? super String> contravariantList = aList;

You can now access all methods of covariantListthat doesn't take a generic parameter (as it mustbe something "extends Object"), but getters will work fine (as the returned object will always be of type "Object")

您现在可以访问所有covariantList不带泛型参数的方法(因为它必须是“扩展对象”的东西),但是 getter 可以正常工作(因为返回的对象将始终是“对象”类型)

The opposite is true for contravariantList: You can access all methods with generic parameters (you know it must be a superclass of "String", so you can always pass one), but no getters (The returned type may be of any other supertype of String)

情况正好相反contravariantList:您可以使用泛型参数访问所有方法(您知道它必须是“String”的超类,因此您始终可以传递一个),但不能访问 getter(返回的类型可能是 String 的任何其他超类型)

回答by extraneon

Look at the Liskov substitution principle. In effect, if class B extends class A then you should be able to use a B whenever an A is required.

看看Liskov 替换原则。实际上,如果 B 类扩展了 A 类,那么您应该能够在需要 A 时使用 B。

回答by Yardena

Co-variance: Iterable and Iterator.It almost always makes sense to define a co-variant Iterableor Iterator. Iterator<? extends T>can be used just as Iterator<T>- the only place where the type parameter appears is the return type from the nextmethod, so it can be safely up-cast to T. But if you have Sextends T, you can also assign Iterator<S>to a variable of type Iterator<? extends T>. For example if you are defining a find method:

协方差:可迭代和迭代器。定义一个协变体Iterableor几乎总是有意义的IteratorIterator<? extends T>可以用作Iterator<T>- 唯一出现类型参数的地方是方法的返回类型next,因此可以安全地向上转换为T. 但是如果你有S扩展T,你也可以分配Iterator<S>给一个类型的变量Iterator<? extends T>。例如,如果您正在定义一个 find 方法:

boolean find(Iterable<Object> where, Object what)

you won't be able to call it with List<Integer>and 5, so it's better defined as

您将无法使用List<Integer>and调用它5,因此最好将其定义为

boolean find(Iterable<?> where, Object what)

Contra-variance: Comparator.It almost always makes sense to use Comparator<? super T>, because it can be used just as Comparator<T>. The type parameter appears only as the comparemethod parameter type, so Tcan be safely passed to it. For example if you have a DateComparator implements Comparator<java.util.Date> { ... }and you want to sort a List<java.sql.Date>with that comparator (java.sql.Dateis a sub-class of java.util.Date), you can do with:

逆变:比较器。使用它几乎总是有意义的Comparator<? super T>,因为它可以像Comparator<T>. 类型参数仅作为compare方法参数类型出现,因此T可以安全地传递给它。例如,如果您有 aDateComparator implements Comparator<java.util.Date> { ... }并且您想List<java.sql.Date>使用该比较器对 a 进行排序(java.sql.Date是 的子类java.util.Date),您可以使用:

<T> void sort(List<T> what, Comparator<? super T> how)

but not with

但不是与

<T> void sort(List<T> what, Comparator<T> how)