举例说明在 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
Give examples of functions which demonstrate covariance and contravariance in the cases of both overloading and overriding in Java?
提问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 covariantList
that 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 Iterable
or 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 next
method, so it can be safely up-cast to T
. But if you have S
extends T
, you can also assign Iterator<S>
to a variable of type Iterator<? extends T>
. For example if you are defining a find method:
协方差:可迭代和迭代器。定义一个协变体Iterable
or几乎总是有意义的Iterator
。Iterator<? 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 compare
method parameter type, so T
can 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.Date
is 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)