当前位置: 首页 > 面试题库 >

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

郭俊拔
2023-03-14
问题内容

标识符在 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”吗?


问题答案:

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妨碍JIT(即时)编译的情况,其可跨平台移植的字节码被JVM“解释”。但是,我真的不知道字节码是什么,以及JVM在Java语言体系结构中的实际含义。我想进一步了解他们。 问题答案: JVM(Java虚拟机)具有与真实计算机一样的指令集。给该指令集的名称是Java字节码。在Java虚拟机规范中对其进行了描述。其他语言在执行之前会被翻译成字节码,例如ruby和python

  • 问题内容: 我一直想知道为什么我们不能在python中的函数名和变量名之间使用连字符 尝试过使用Lisp和Clojure之类的功能编程语言,允许使用连字符。为什么python不这样做。 我确信,由于某些原因,圭多爵士一定会这样做。我用谷歌搜索,但找不到答案。谁能给我一点启示吗? 问题答案: 因为连字符用作减法运算符。想象一下,您 可以 拥有一个函数,然后拥有如下代码: 是对函数的调用,还是从名为的

  • 问题内容: 来自C语言的Go语言最值得注意的方面之一是,如果在其中声明了一个未使用的变量,编译器将不会编译您的程序。那么,如果在函数中声明了一个未使用的参数,那么为什么要构建此程序呢? 问题答案: 没有正式的原因,但是在golang-nuts上给出的原因是: 未使用的变量始终是编程错误,而编写不使用其所有参数的函数是很常见的。 可以将这些参数保留为未命名(使用_),但这可能会与诸如 func fo

  • 问题内容: 我刚接触PHP,但是多年来我一直在使用类似的语言进行编程。我被以下内容弄糊涂了: 它产生了语法错误:这就是调用。 但这很好用: 碰了一会儿之后,我被告知您不能在默认属性中调用函数。你必须在做。我的问题是:为什么?这是“功能”还是草率的实现?有什么根据? 问题答案: 编译器代码建议这是设计使然,尽管我不知道其背后的官方原因是什么。我也不确定要可靠地实现此功能需要花费多少精力,但是目前完成

  • 我一直在捕捉非数字时遇到问题。 我试过了,但抓不住。如果我让它捕获非数字,但不让用户再次尝试输入。。。它完全停止了我的代码。 这是我的密码:

  • 问题内容: 我最近了解到,Java源代码中不仅允许将Unicode字符作为Unicode字符(例如),还允许将其作为转义序列(例如)。 第一个变体对我来说很有意义-它允许程序员使用他们选择的国际语言来命名变量和方法。但是,我看不到第二种方法的任何实际应用。 以下是一些使用Java SE 6和NetBeans 6.9.1进行测试的说明用法的代码: 此代码将打印出3.141592653589793 说