Java 为什么参数化方法在某些情况下可以隐式绑定,而在其他情况下则不能?
我最近在重构代码时遇到了这个问题: 下面的方法“getList()”具有参数化的返回类型。下面,我列出了三种方法,它们试图将Java 为什么参数化方法在某些情况下可以隐式绑定,而在其他情况下则不能?,java,generics,Java,Generics,我最近在重构代码时遇到了这个问题: 下面的方法“getList()”具有参数化的返回类型。下面,我列出了三种方法,它们试图将隐式绑定到 我不明白的是,为什么前两个编译并正确运行,而第三个(bindViaMethodInvocation)甚至无法编译 有什么线索吗 在寻找有关StackOverflow的类似问题时,我遇到了以下问题: . 答案(信贷)有几个有用的参考链接来解释应该发生什么: “这里的问题(正如您所建议的)是编译器正在执行。我相信这是JLS的结果。” 包堆栈溢出; 导入java.u
隐式绑定到
我不明白的是,为什么前两个编译并正确运行,而第三个(bindViaMethodInvocation)甚至无法编译
有什么线索吗
在寻找有关StackOverflow的类似问题时,我遇到了以下问题:
. 答案(信贷)有几个有用的参考链接来解释应该发生什么:
“这里的问题(正如您所建议的)是编译器正在执行。我相信这是JLS的结果。”
包堆栈溢出;
导入java.util.*;
公共类参数化返回
{
//参数化方法
公共静态列表getList()
{
返回新的ArrayList();
}
公共静态列表bindViaReturnStatement()
{
返回getList();
}
公共静态列表bindViaVariableAssignment()
{
List intList=getList();
返回intList;
}
公共静态列表bindViaMethodInvocation()
{
//此处编译错误
返回echo(getList());
}
公共静态列表回显(List intList)
{
返回intList;
}
}
前两个方法在要进行赋值转换的上下文中使用getList()
——要么是对List
的赋值,要么是返回List
的方法的返回语句。对于bindViaMethodInvocation
,情况并非如此-将表达式用作方法参数不受赋值转换的约束
从:
如果该方法的任何类型参数不是从实际参数的类型推断出来的,那么现在将按如下方式推断它们
- 如果方法结果发生在将进行赋值转换(§5.2)为类型S的上下文中,则让R为方法的声明结果类型,并让R'=R[T1=B(T1)…Tn=B(Tn)],其中B(Ti)为上一节中为Ti推断的类型,或者如果未推断类型,则为Ti
getList()
的含义因环境而异,这对Java程序员来说是违反直觉的(以前从未有过),因此前两个编译,而第三个不编译,这让人感到困惑。你不是一个人,这种问题已经被反复提出。他们可以告诉我们如何使用RTF,但是一个人越需要阅读规范,规范就越糟糕
当然,如果上下文相关的解释真的有用和必要,我们就必须实用。然而,几乎没有证据支持这一点。这种类型的推断非常危险,使用它的大多数代码99%都是错误设计的。现在还不清楚他们的想法是什么,他们认为有必要添加这种类型推断规则
如果Java泛型被“具体化”,即T
的值在运行时可用于方法调用,我们可以想象这样的类型推断是安全和有用的。但是,T
在运行时不可用,因此getList()
调用是上下文无关的,不可能返回调用站点所期望的正确类型。除非有一些语言外的应用程序逻辑来保护类型的可靠性。那就很难说是“静态类型”
有些人更进一步,要求进行以下类型推断:
Object getFoo(){ .. }
Bar bar = getFoo();
因为“如果我写了这个,我当然知道运行时返回类型是Bar,所以别再问我了,愚蠢的编译器!”
我尊重这种观点,但你应该选择不同的语言。在静态和动态类型中,编程人员都知道类型,但是静态类型的要点是,无论如何,我们都要明确地在源代码中写下类型——不是为了帮助编译器,而是为了让我们自己受益。“类型推断”违背了这个确切的目标;只有当它不会对任何阅读代码的人造成任何关于类型真正是什么的神话时,才应该这样做。不幸的是,Java的类型推断非常神秘 谢谢你,马特!我想我没有正确地对这些进行降价。
Object getFoo(){ .. }
Bar bar = getFoo();