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

时间:2015-08-28 00:46:37

标签: java java-8

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

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

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

void m() { }

void test() {
    m(); 
    this.m(); 
    this.<Integer>m(); // Compiles and runs OK!
    this.<String, Byte, StringBuilder, Thread[], Throwable>m(); // Compiles and runs OK!
    <Integer>m(); // Won't compile: "illegal start of expression"
}

我有几个问题出现了:

  1. 任何人都可以建议Java允许这些冗余类型参数的正当理由吗?接受它们没有伤害,在我看来,编译器可以并且应该抓住这些东西。

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

  3. (这些问题的催化剂是Oracle's response我为一个有趣的Java问题创建的错误报告,有人在SO上提出了here。)

    2015年9月18日更新

    1. 我针对此问题向Oracle提出bug JDK-8098556。以下是他们的回复:
    2. 这不是问题;使用与普通方法相同的规则检查方法引用 - 请注意,对于普通方法,您始终可以提供冗余类型参数:

      void m() { }
      this.<String>m(); //legal
      

      方法(和构造函数)引用只是继承了这种行为,如15.13所示: “”如果方法引用表达式具有ReferenceType :: [TypeArguments]标识符的形式,则可能适用的方法是要搜索的类型的成员方法,其具有适当的名称(由标识符给出),可访问性,arity(n或n- 1),并键入参数arity(派生自[TypeArguments]),如§15.12.2.1中所述。“

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

1 个答案:

答案 0 :(得分:5)

以下是方法调用的方法

  

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.<Integer>m();//Also compiles
}

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

  

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

代表JLS 15.12.2.1的以下陈述,

  

本条款暗示非通用方法可能 potentially   适用于提供显式类型参数的调用。   实际上,它可能会变得适用。在这种情况下,类型   参数只是 忽略

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

此外,

  

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