Java 类文件可以使用保留关键字作为名称吗?

2022-08-31 16:08:11

我知道Java-the-comcompable-programming-language与Java-the-bytecode-format-for-JVM-execution不是一回事。有些示例在 .class 格式中有效,但在源代码.java无效,例如无构造函数类和综合方法。

  1. 如果我们使用保留的 Java 语言关键字(例如 ,)作为类、方法或字段名称手工制作一个.class文件,Java 虚拟机会接受它进行加载吗?intwhile

  2. 如果加载了该类,这是否意味着访问该类或成员的唯一方法是通过Java反射,因为该名称在Java编程语言中在语法上是非法的?


答案 1

是的,您可以使用保留字。这些单词仅适用于编译器。它们不会出现在生成的字节代码中。

使用保留 Java 字的一个例子是基于 JVM 的 Scala 语言。Scala具有与Java不同的构造和语法,但编译为Java字节代码,以便在JVM上运行。

这是合法的 Scala:

class `class`

这定义了一个以无参数构造函数命名的类。在已编译文件上运行(反汇编程序)显示classjavapclass.class

public class class {
    public class();
}

Scala可以对任何其他Java保留字做同样的事情。

class int
class `while`
class goto

它们还可用于方法或字段名称。

正如你所怀疑的那样,除了反射之外,你将无法从Java使用这些类。您可以从类似的“自定义”类文件中使用它们,例如从Scala编译器生成的类文件中使用它们。

总而言之,这是javac(编译器)的限制,而不是java(VM/运行时环境)。


答案 2

在字节码级别对类名的唯一限制是它们不能包含字符,或者它们最多有65535个字节长。除此之外,这意味着您可以自由使用保留字,空格,特殊字符,Unicode,甚至是换行符等奇怪的东西。[.;

从理论上讲,您甚至可以在类名中使用空字符,但是由于文件名中不可能有空字符,因此您不能在jar中包含这样的类文件。不过,您也许能够动态创建和加载一个。

以下是您可以执行的一些操作的示例(用 Krakatau 程序集编写):

; Entry point for the jar
.class Main
.super java/lang/Object

.method public static main : ([Ljava/lang/String;)V
    .limit stack 10
    .limit locals 10
    invokestatic int                                hello ()V
    invokestatic "-42"                              hello ()V
    invokestatic ""                                 hello ()V
    invokestatic "  some  whitespace and \t tabs"   hello ()V
    invokestatic "new\nline"                        hello ()V
    invokestatic 'name with "Quotes" in it'         hello ()V
    return
.end method
.end class


.class int
.super java/lang/Object
.method public static hello : ()V
    .limit stack 2
    .limit locals 0
    getstatic java/lang/System out Ljava/io/PrintStream;
    ldc "Hello from int"
    invokevirtual java/io/PrintStream println (Ljava/lang/Object;)V
    return
.end method
.end class

.class "-42"
.super java/lang/Object
.method public static hello : ()V
    .limit stack 2
    .limit locals 0
    getstatic java/lang/System out Ljava/io/PrintStream;
    ldc "Hello from -42"
    invokevirtual java/io/PrintStream println (Ljava/lang/Object;)V
    return
.end method
.end class

; Even the empty string can be a class name!
.class ""
.super java/lang/Object
.method public static hello : ()V
    .limit stack 2
    .limit locals 0
    getstatic java/lang/System out Ljava/io/PrintStream;
    ldc "Hello from "
    invokevirtual java/io/PrintStream println (Ljava/lang/Object;)V
    return
.end method
.end class

.class "  some  whitespace and \t tabs"
.super java/lang/Object
.method public static hello : ()V
    .limit stack 2
    .limit locals 0
    getstatic java/lang/System out Ljava/io/PrintStream;
    ldc "Hello from   some  whitespace and \t tabs"
    invokevirtual java/io/PrintStream println (Ljava/lang/Object;)V
    return
.end method
.end class

.class "new\nline"
.super java/lang/Object
.method public static hello : ()V
    .limit stack 2
    .limit locals 0
    getstatic java/lang/System out Ljava/io/PrintStream;
    ldc "Hello from new\nline"
    invokevirtual java/io/PrintStream println (Ljava/lang/Object;)V
    return
.end method
.end class

.class 'name with "Quotes" in it'
.super java/lang/Object
.method public static hello : ()V
    .limit stack 2
    .limit locals 0
    getstatic java/lang/System out Ljava/io/PrintStream;
    ldc "Hello from name with \"Quotes\" in it"
    invokevirtual java/io/PrintStream println (Ljava/lang/Object;)V
    return
.end method
.end class

执行输出:

Hello from int
Hello from -42
Hello from
Hello from   some  whitespace and        tabs
Hello from new
line
Hello from name with "Quotes" in it

请参阅 Holger 的答案,了解 JVM 规范中规则的确切引用。