JVM为什么允许我们用字节码中的数字开头的函数命名?

问题描述

Java语言规范对有效方法名称中的字符进行了限制,以帮助解析Java语言。

JVM设计为能够支持Java以外的其他语言。因此,限制不应相同;除非我们要强制所有非Java语言都具有相同的限制。为JVM选择的限制是允许对方法签名进行明确解析的最小设置,这种格式出现在JVM规范而非JLS中。

取自JVM Spec

a name must not contain any of the ASCII characters . ; [ / < > :

也就是说,以下是有效的JVM签名[Lcom/foo/Bar;,并且其特殊字符已从方法名称中排除。

<>进一步保留了将特殊的JVM方法与应用程序方法分开的方法,特别是<init><clinit>,这都是JLS不允许的方法名称

解决方法

标识符在 Java SE 7 Edition (第3.8节)中明确定义。

An identifier is an unlimited-length sequence of Java letters and Java

digits,the
first of which must be a Java letter.

据我所知,由于方法名是一个标识符,因此在Java中以数字开头的方法应该是不可能的,并且javac遵守这一规则。

那么,为什么Java虚拟机似乎不允许我们以字节码命名以数字开头的函数,所以似乎不遵守该规则?


这个简单的代码片段实际上将打印f99()方法名称及其参数的值。

public class Test {
    public static void main(String[] args) {
        Test t = new Test();
        System.out.println(t.f99(100));
    }

    public int f99(int i){
        System.out.println(Thread.currentThread().getStackTrace()[1].getMethodName());
        return i;
    }
}

编译与执行:

$ javac Test.java
$ java Test

输出:

f99
100

可以在编译后反汇编代码,并f99通过99(在诸如reJ之类的工具的帮助下
)重命名所有出现的代码。

$ java Test

输出:

99
100

那么,该方法的名称实际上是“ 99”吗?