我已经在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
。除此之外,你实际提供的类型参数不应该有任何区别。因此,如果在第二种情况下类型参数是冗余的,那么在第一种情况下它应该是多余的。任何人都可以解释这些消息何时出现的规则是什么,以及为什么在这种情况下规则甚至应该依赖于提供的类型参数?
答案 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)
将无法编译,因为Integer
与Long
不兼容。
答案 2 :(得分:1)
关于通用方法的文档https://docs.oracle.com/javase/tutorial/extra/generics/methods.html
请注意,我们不必将实际类型参数传递给泛型方法。编译器根据实际参数的类型为我们推断类型参数。它通常会推断出使调用类型更正的最具体的类型参数。
由于Integer是您的案例中最具体的类型,因此指定它是多余的。由于Number是更通用的类型,因此不是多余的。
另外,由于类型擦除,两个调用中没有运行时差异,这是正确的。
答案 3 :(得分:0)
此处的其他答案解释了为什么可以省略类型参数。
至于为什么这首先是一个警告,这是因为你的代码是多余的。 DRY原则说你永远不应该编写冗余代码,因此IDE的编译器会帮助你警告你编写了冗余的,不必要的代码。
即使(有些人会特别说)如果它对编译结果或运行时的行为没有影响,仍然值得删除冗余代码。所以我认为这是一个很好的警告,最好遵循它的建议。