Java Isn';参数类型不是反变量吗?

Java Isn';参数类型不是反变量吗?,java,scala,Java,Scala,我理解协方差和逆变换这两个术语。但有一件小事我无法理解。在coursera的“Scala函数编程”课程中,Martin Ordersky提到: 函数在参数类型上是逆变的,在参数类型上是共变的 他们的回报类型 例如,在Java中,让Dog扩展Animal。设一个函数为: void getSomething(Animal a){ 我的函数调用是 Dog d = new Dog(); getSomething(d) 所以基本上发生的是动物a=d。根据协方差,是“由宽变窄”。更重要的是,我们正在从狗

我理解协方差和逆变换这两个术语。但有一件小事我无法理解。在coursera的“Scala函数编程”课程中,Martin Ordersky提到:

函数在参数类型上是逆变的,在参数类型上是共变的 他们的回报类型

例如,在Java中,让
Dog
扩展
Animal
。设一个函数为:

void getSomething(Animal a){
我的函数调用是

Dog d = new Dog();
getSomething(d)

所以基本上发生的是动物a=d。根据协方差,是“由宽变窄”。更重要的是,我们正在从狗变成动物。因此,论点类型不是协变的,而是逆变的吗?

将狗转换成动物是从窄到宽,所以它不是协变的。

我记得2007年读Scala书时,我被这句话弄糊涂了。Martin的演讲就像是在谈论一种语言功能,但在那句话中,他只陈述了一个关于一般功能的事实。具体来说,Scala仅通过一个常规特征对这一事实进行建模。由于Scala具有声明站点差异,因此表达这些语义对于语言来说是很自然的

另一方面,Java泛型只支持使用站点差异,因此在Java中,最接近函数类型的协变/逆变是在每个使用站点手工编码:

public int secondOrderFunction(Function<? super Integer, ? extends Number> fn) {
     ....
}
public int secondOrderFunction(函数这是:

在英语中,参数
T1
是逆变的,结果类型
R
是协变的。这是什么意思

当某段代码需要
Dog=>Animal
type函数时,由于参数的逆变,您可以提供
Animal=>Animal
type函数(您可以使用更广泛的type)

由于结果类型的协方差,您还可以提供
Dog=>Dog
类型的函数(您可以使用更窄的类型)


这实际上是有道理的:有人想要一个能将狗转化为任何动物的函数。你可以提供一个能转化任何动物(包括狗)的函数。此外,您的函数只能返回狗,但狗仍然是动物。

我认为关于将狗转换为动物的原始问题已经澄清,但可能需要注意的是,函数在其参数中定义为逆变函数,在其返回类型中定义为协变函数是有原因的。假设您有两个函数:

valf:脊椎动物=>哺乳动物=???
val g:哺乳动物=>灵长类=???

当我们谈论函数时,您可能会期望处于原始操作中。实际上,您可以组合f和g(GOF),并获得一个函数:

val h:脊椎动物=>Primate=f和第g

但我可以用子类型替换
g

val gChild:Animal=>Primate

在不破坏可组合性的情况下,
gChild
g
的一个子类型,这正是因为我们在其参数中定义了函数逆变。作为结论,您可以看到,如果您想要捕获并保留函数可组合性的概念,必须以这种方式定义函数。
你可以找到更多的细节和一些有助于理解这一主题的图表

还有这样一句话:“函数在其参数类型中是逆变的,在其返回类型中是协变的”在Java环境中无效?目前,是的,但不是说它声明了Java函数的虚假性,而是说它声明了Java中不存在的实体。实际上,Scala也没有函数类型。Scala中的函数只是带有单个方法的常规对象。事实上,Scala中的函数完全是伪造的与Java.Co中的方法相同,函数参数和返回值的逆变同样适用于Java
接口函数1
,正如它适用于Scala
特征函数1[T,R]
。有人说要在Java中添加函数类型,但不是在Java 9之前。只是想知道,BGGA提案不是有一个完整的函数类型层次结构吗?另一件事是,逆变类型只能出现在您编写内容(即参数类型)的地方协变类型只能出现在一些地方,在这些地方你读到了一些东西(即返回类型),加上“额外的东西”并没有扩大定义范围,而是缩小了定义范围,因为符合最具体的子类(狗)的对象少于更一般的(动物).动物的定义更广泛,即接受更多可能的实例。另见
trait Function1 [-T1, +R]  extends AnyRef