与Java方法调用中的类型参数相关的问题

Java 8 Java语言规范提供了一个带有类型参数的方法调用示例,例如“示例4.11-1。类型的用法”:

 void loop(S s) { this.loop(s); //  is the the type argument for the method call. } 

在该示例中,提供的类型参数是有意义的,但显然方法调用的类型参数也可能是多余的并且完全没有意义,甚至不需要涉及generics。 例如:

 void m() { } void test() { m(); this.m(); this.m(); // Compiles and runs OK! this.m(); // Compiles and runs OK! m(); // Won't compile: "illegal start of expression" } 

我有几个问题出现:

  1. 任何人都可以建议Java允许这些冗余类型参数的正当理由吗? 接受它们没有伤害,我似乎仍然喜欢编译器能够并且应该捕获的东西。

  2. 如果使用类型参数调用方法前缀为“this”,则该代码仅编译。 否则你会得到“非法开始表达”错误。 那是一个错误吗? 不应该使用任何明确的方法调用“this”。 没有“这个”也能工作吗?

(这些问题的催化剂是Oracle对我为一个有趣的Java问题创建的错误报告的回应 。

更新2015年9月18日

  1. 我在Oracle上针对这个问题提出了错误JDK-8098556 。 以下是他们的回复:

这不是问题 ; 使用与普通方法相同的规则检查方法引用 – 请注意,对于普通方法,您始终可以提供冗余类型参数:

 void m() { } this.m(); //legal 

方法(和构造函数)引用只是inheritance了这种行为,按照15.13:“”如果方法引用表达式的forms为ReferenceType :: [TypeArguments] Identifier,则可能适用的方法是要搜索的类型的成员方法name(由Identifier提供),accessibility,arity(n或n-1)和type argument arity(派生自[TypeArguments]),如§15.12.2.1中所述。“

  1. 由于该回复确认了TAsk已经在下面提供的信息(包括引用JLS的相关部分),我已经接受了这个答案。

以下是方法调用的方法:

JLS 15.12列出了以下调用方法的方法,

  • MethodName ( [ArgumentList] ) (注意:这里没有类型参数)
  • TypeName.[TypeArguments] Identifier ( [ArgumentList] )
  • ExpressionName.[TypeArguments] Identifier ( [ArgumentList] )
  • Primary.[TypeArguments] Identifier ( [ArgumentList] )
  • super.[TypeArguments] Identifier ( [ArgumentList] )
  • TypeName.super.[TypeArguments] Identifier ( [ArgumentList] )

因此,在Java语言规范中,带有表达式或类型名称的方法可以具有类型参数,但请注意,在第一个方法调用中,您不能指定类型参数,因为它是非法的。

请注意,只有this没有允许这个,但static调用和super方法调用也可以有类型参数,这些是完全合法的。

 static void m() { } void test() { ClassName.m();//Also compiles } 

除此之外,您将收到以下警告:

非generics方法m()的未使用类型参数

以下是JLS 15.12.2.1的以下陈述,

此子句意味着非generics方法可能适用于提供显式类型参数的调用。 实际上,它可能适用。 在这种情况下,类型参数将被忽略

确实,它可能适用 (在运行时)

此外,

该规则源于兼容性和可替代性原则的问题 由于接口或超类可以独立于其子类型进行生成,因此我们可以使用非generics方法覆盖generics方法。 但是,重写(非generics)方法必须适用于对generics方法的调用,包括显式传递类型参数的调用。 否则,子类型不能替代其生成的超类型。