【问题标题】:Why will the compiler accept an invalid syntax call (<?>method) when statically called?为什么编译器在静态调用时会接受无效的语法调用(<?>方法)?
【发布时间】:2015-03-02 21:46:26
【问题描述】:

是否存在在方法之前没有静态/实例引用无法调用 Java 通用方法的原因?如示例代码中的“case 2”和“case 5”。

换句话说,为什么我们可以在没有静态/实例引用的情况下调用普通方法(如“案例 3”)而在通用方法中却不能?

public class MyClass {

public static void main(String[] args) {

    MyClass.<String>doWhatEver("Test Me!"); // case 1

    <String>doWhatEver("Test Me2!"); // case 2 COMPILE ERROR HERE

    doSomething("Test Me 3!"); // case 3 (just for compare)

    new MyClass().<String>doMoreStuff("Test me 4"); // case 4

}

public void doX(){
    <String>doMoreStuff("test me 5"); // case 5 COMPILE ERROR HERE
}


public static <T> void doWhatEver(T x){
    System.out.println(x);
}

public static void doSomething(String x){
    System.out.println(x);
}

public <T> void doMoreStuff(T x){
    System.out.println(x);
}

}

【问题讨论】:

  • AFAIK &lt;T&gt;someMethod() 不是一个有效的语法..
  • 这是一个语法错误。不过你不需要&lt;...&gt;,编译器通常会推断出正确的类型。
  • @AdrianLeonhard 是的,我知道,但不是语法错误,如果您对案例 2 和案例 5 进行注释,它会编译并运行。在某些情况下,某些 API 必须使用这些语法。
  • @RC。你在哪里看到这个“someMethod()”?是 someMethod(T t) 。这是法律代码
  • @NESPowerGlove 是的,因为您可以在没有实例/静态引用的情况下使用普通方法调用,而通用方法则不能......

标签: java generics methods


【解决方案1】:
  • 您无需为案例 1 和 4 指定 &lt;String&gt;,编译器会为您处理。
  • 现在让我们尝试运行您的示例,看看会发生什么。

线程“主”java.lang.RuntimeException 中的异常:无法编译 源代码 - 表达式的非法开始

就这么简单,你的问题的答案是因为语法无效,它不应该在javac规范中使用。

但是,这与是否为static 无关。在构造函数中尝试删除 doWhatEver 方法的 static 关键字:

public MyClass()
{
    <String>doWhatEver("Test Me2!"); //does not compile
    doWhatEver("Test Me2!"); //compile
}

public <T> void doWhatEver(T x){
    System.out.println(x);
}

现在,如果您想知道为什么 MyClass.&lt;String&gt;doWhat.. 编译了,而 &lt;String&gt;doWhat.. 即使我们修改了 static 关键字也没有编译,让我们看看生成的字节码。

你的行会被编译成这样:

6: invokestatic  #5                  // Method doWhatEver:(Ljava/lang/Object;)V

哪个更正了您所犯的语法错误,但为什么?

尝试编译例如这两行

MyClass.<String>doWhatEver("Test Me2!");
MyClass.doWhatEver("Test Me3!");

然后在 .class 文件上运行javap -v,您会注意到这两个调用都编译为相同的字节码。

4: ldc           #4                  // String Test Me2!
6: invokestatic  #5                  // Method doWhatEver:(Ljava/lang/Object;)V
9: ldc           #6                  // String Test Me3!
11: invokestatic  #5                  // Method doWhatEver:(Ljava/lang/Object;)V

如果您调用非静态方法,生成的字节码将改为invokevirtual

17: invokevirtual #8                  // Method doWhatEver2:(Ljava/lang/Object;)V

我的猜测是invokestatic 将直接在常量池(存储静态方法的地方)中搜索与指定调用对应的方法并省略类型声明,而invokevirtual 将在实际类中搜索。

【讨论】:

  • 非常好的答案,tnx 这么多。而且我刚刚找到了语法规范。规则是,如果是泛型方法,则必须使用 super()/this/reference 变量/或 Class(如果是静态的)调用。
猜你喜欢
  • 2012-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-02
相关资源
最近更新 更多