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

Pie*_*ard 3 java jvm bytecode identifier

标识符由Java语言规范,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.
Run Code Online (Sandbox Code Playgroud)

据我所知,由于方法名称是标识符,因此不可能在java中命名以数字开头的方法,并javac遵守此规则.

那么,为什么Java虚拟机似乎不遵守这个规则,允许我们在Bytecode中命名一个以数字开头的函数?


这个简单的代码片段实际上会打印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;
    }
}
Run Code Online (Sandbox Code Playgroud)

编译和执行:

$ javac Test.java
$ java Test
Run Code Online (Sandbox Code Playgroud)

输出:

f99
100
Run Code Online (Sandbox Code Playgroud)

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

$ java Test
Run Code Online (Sandbox Code Playgroud)

输出:

99
100
Run Code Online (Sandbox Code Playgroud)

那么,方法的名称实际上是"99"吗?

Chr*_*s K 7

Java语言规范限制有效方法名称中的字符,以帮助使Java语言的解析明确无误.

JVM旨在支持Java以外的语言.因此,限制不应相同; 除非我们想强制所有非Java语言具有相同的限制.为JVM选择的限制是允许对方法签名进行明确解析的最小集合,这种格式出现在JVM规范中而不是JLS中.

取自JVM Spec

a name must not contain any of the ASCII characters . ; [ / < > :
Run Code Online (Sandbox Code Playgroud)

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

<>进一步保留以分离从施用方法,具体地特别JVM方法<init><clinit>,它们是在JLS不允许两个方法名.

  • @Azar - 它不一定是"构建"来支持其他语言(尽管还有其他一些语言没有运行JVM).相反,根本没有必要限制名称,为什么在没有需要时限制? (3认同)

Cir*_*四事件 5

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

真正的程序员不使用解析器,他们使用sed

javac Test.java
sed -i 's/\d003f99/\d00299/' Test.class
java Test
Run Code Online (Sandbox Code Playgroud)

输出:

99
100
Run Code Online (Sandbox Code Playgroud)

这是可行的,因为我们知道方法名称以Utf8 条目的明文形式存储在常量池中,并且 JVMS 表示 Utf8 条目的格式为

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}
Run Code Online (Sandbox Code Playgroud)

所以我们有类似的东西:

01 | 00 03 | 'f' '9' '9'
Run Code Online (Sandbox Code Playgroud)

(标识符 3 字节长)并将 sed 命令替换03 | 'f' '9' '9'02 | '9' '9'(现在 2 字节长)。

后来我检查了一下,javap -v Test.classsed做了我想做的事情。前:

#18 = Utf8               f99
Run Code Online (Sandbox Code Playgroud)

后:

#18 = Utf8               99
Run Code Online (Sandbox Code Playgroud)

经过手动编辑、运行、反编译并.class与 JVMS 进行比较后,我只能得出结论:方法名称必须是99:-)

所以这只是字节码中不存在的 Java 语言限制。

为什么 Java 禁止使用这样的名称?

可能使语法看起来像 C。

不以数字开头可以让人类和解析器更轻松地区分标识符和整数文字。

也可以看看: