冗余类型参数

时间:2015-09-06 02:33:08

标签: java generics

我已经在IntelliJ中编写了这个类。

public class Main  {

    public static void main(String[] args) {
        Main.<Number>foo(0);
        Main.<Integer>foo(0);
    }

    static <T> void foo(T t) {}
}

Main.<Number>foo(0);不生成任何消息,但在下一行我收到消息

  

可以推断显式类型参数。   此检查报告所有对参数化方法的调用   显式参数类型可以省略,因为它们将是   由编译器明确推断。

这根本不对我有任何意义。我的理解是所有类型的参数都被删除了,因此类型参数是否含糊不应无关紧要。据我所知,在调用带有void返回类型的泛型方法时,提供类型参数的唯一原因是要说服编译器在所需的边界内存在类型T。除此之外,你实际提供的类型参数不应该有任何区别。因此,如果在第二种情况下类型参数是冗余的,那么在第一种情况下它应该是多余的。任何人都可以解释这些消息何时出现的规则是什么,以及为什么在这种情况下规则甚至应该依赖于提供的类型参数?

4 个答案:

答案 0 :(得分:2)

我从未见过这条消息,但它看起来像是一个警告。

首先观察到这来自Intellij编译器。当我使用Java 8 javac编译它时,没有这样的警告消息。

另外需要注意的是,在这种情况下,编译器在这里推断T的类型没有区别。我认为这就是编译器告诉你的。

如果方法返回T并且您将结果分配给变量(例如),则可能无关紧要。例如:

   Integer i = Main.<Integer>foo(0);  // OK
   i = Main.foo(0);                   // OK
   i = Main.<Long>foo(0L);            // Error
   i = Main.foo(0L);                  // Different error message.

在第三种情况下,(javac)编译器表示不能将Long分配给Integer

在最后一种情况下,(javac)编译器推断foo将返回Long,并且表示无法分配推断类型。

  

我无法理解为什么你必须提供类型参数。

考虑将foo调用的结果用作重载方法的参数的情况,并且需要特定的结果类型才能让Java调用正确的重载。

值得注意的是,Java 8的类型推断比早期版本更复杂。可能存在旧版Java的情况,其中推理需要以显式类型参数的形式提供一些帮助。

答案 1 :(得分:2)

这只是一个警告,说明不需要指定类型。

由于T是一个对象,并且不能是一个原语,0参数将被装箱为Integer。这意味着编译器会推断T表示Integer,因此指定它是多余的。

无论您指定的类型参数如何,参数都会被设置为整数。例如。 Test.<Long>foo(0)将无法编译,因为IntegerLong不兼容。

答案 2 :(得分:1)

关于通用方法的文档https://docs.oracle.com/javase/tutorial/extra/generics/methods.html

  

请注意,我们不必将实际类型参数传递给泛型方法。编译器根据实际参数的类型为我们推断类型参数。它通常会推断出使调用类型更正的最具体的类型参数。

由于Integer是您的案例中最具体的类型,因此指定它是多余的。由于Number是更通用的类型,因此不是多余的。

另外,由于类型擦除,两个调用中没有运行时差异,这是正确的。

答案 3 :(得分:0)

此处的其他答案解释了为什么可以省略类型参数。

至于为什么这首先是一个警告,这是因为你的代码是多余的。 DRY原则说你永远不应该编写冗余代码,因此IDE的编译器会帮助你警告你编写了冗余的,不必要的代码。

即使(有些人会特别说)如果它对编译结果或运行时的行为没有影响,仍然值得删除冗余代码。所以我认为这是一个很好的警告,最好遵循它的建议。