Java 7泛型类型推断:返回值与方法参数

25

为什么编译器能够正确推断函数返回类型中的String类型参数。

public class Generics {
    private static List<String> function() {
        return new ArrayList<>();
    }
}

但当需要推断的类型是一个方法参数时,它会失败:

public class Generics {
    public static void main(String[] args) {
        method(new ArrayList<>());
    }    

    private static void method(List<String> list) {

    }
}

这种情况下的错误是:

The method method(List<String>) in the type Generics is not applicable 
for the arguments (ArrayList<Object>)

7
因为他们没有在所有可能的地方实现泛型类型推断。我没有测试过这个特定的案例,但Java 8在类型推断方面带来了很多改进,以帮助处理lambda表达式。 - JB Nizet
1
这是因为完美的类型推断在有限时间内解决起来太困难了(它与停机问题的复杂度相同)。因此,Java开发人员不得不在某个地方划定界限。正如其他人所指出的那样,他们不断地将界限推得更远,但某些限制必须存在。 - Konstantin Tarashchanskiy
1
@KonstantinNaryshkin:对Java 8的工作表明,他们划定了太早的界限。更有用的规则是可能的,并且正在Java 8中被整合。很容易说第一次应该推得更远,但很难预测哪些额外的工作会带来实际的好处。总的来说,最初的实现非常有用。但它本可以更早地得到改进。 - Joachim Sauer
2个回答

16

这是类型推断目前无法按预期工作的情况之一。

不幸的是,这种行为完全有效且符合规范。

好消息是,Java 8将包含改进的类型推断(JEP101),因此像这样的情况应该会编译成您预期的方式:

当泛型方法调用的结果传递给另一个方法时,编译器应该能够自动推断类型似乎很合理 [...].

不幸的是,在JDK 5/6/7中不允许这样做 - 程序员唯一可用的选项是使用显式类型参数。

除了直接的改进(即像您在此处提到的情况),这种变化还有助于更有效地使用Lambda表达式(JEP126)(即不必输入大量类型信息)。


是的,他们基本上在那里写出了完全相同的示例。 - aglassman
2
似乎Java 8将是自Java 5以来最重要的Java版本。我非常迫不及待地想要开始使用它进行开发。那些仍然必须使用Java 1.4的人,我对他们深表同情。 - gontard

6
在JLS中,有关推断未解决的类型参数的部分相当复杂,但我了解第一种情况中的钻石出现在受到赋值转换影响的地方,而在第二种情况中它出现在方法调用转换中,后者遵循不同的规则。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接