Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java类文件可以使用保留关键字作为名称吗?_Java_Reflection_Jvm_.class File - Fatal编程技术网

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

Java类文件可以使用保留关键字作为名称吗?,java,reflection,jvm,.class-file,Java,Reflection,Jvm,.class File,我知道Java是一种可编译的编程语言,与Java不同,Java是JVM执行的字节码格式。有一些在.class格式中有效但在.java源代码中无效的示例,例如无构造函数类和合成方法 如果我们手工制作一个带有保留Java语言关键字(例如,int,while)的.class文件作为类、方法或字段名,Java虚拟机会接受它进行加载吗 如果加载了该类,是否意味着访问该类或成员的唯一方法是通过Java反射,因为该名称在Java编程语言中在语法上是非法的 关键字只有编译器知道。编译器翻译 将它们转换为足够的字

我知道Java是一种可编译的编程语言,与Java不同,Java是JVM执行的字节码格式。有一些在.class格式中有效但在.java源代码中无效的示例,例如无构造函数类和合成方法

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

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

  • 关键字只有编译器知道。编译器翻译 将它们转换为足够的字节码。所以它们在的运行时不存在 编译的字节码,因此,JVM不会对其进行验证
  • 当然,您不能访问当前未知的类成员 编译时。但是如果你愿意,你可以使用反射来达到这个目的 确保此类类成员将存在于编译代码中(您可以 将“手工制作”它们),因为通过反射进行访问是不可能的 由编译器验证

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

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

    这是合法的Scala:

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

    public class class {
        public class();
    }
    
    Scala可以对任何其他Java保留字执行相同的操作

    class int
    class `while`
    class goto
    
    它们也可以用于方法或字段名

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


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

    字节码级别对类名的唯一限制是它们不能包含字符
    [
    并且它们的长度最多为65535字节。这意味着您可以自由使用保留字、空格、特殊字符、Unicode,甚至是新行等奇怪的东西

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

    以下是您可以做的一些事情的示例(用Krakatau汇编编写):

    执行输出:

    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
    

    有关JVM规范中规则的确切引用,请参阅。

    JVM规范中固定了有关名称的限制:

    出现在类文件结构中的类和接口名称始终以称为二进制名称(JLS§13.1)的完全限定形式表示。此类名称始终表示为
    CONSTANT\u Utf8\u info
    结构(§4.4.7),因此可以从整个Unicode代码空间中绘制(不受进一步限制)

    由于历史原因,类文件结构中出现的二进制名称的语法与JLS§13.1中记录的二进制名称的语法不同。在这种内部形式中,通常分隔构成二进制名称的标识符的ASCII句点(
    )被ASCII正斜杠(
    /
    )取代标识符本身必须是非限定名称(§4.2.2)。

    方法、字段、局部变量和形式参数的名称存储为非限定名称。非限定名称必须至少包含一个Unicode代码点,并且不得包含任何ASCII字符
    [
    /
    (即句点或分号或左方括号或正斜杠)

    方法名称进一步受到限制,因此,除特殊方法名称
    (§2.9)外,它们不得包含ASCII字符
    (即左尖括号或右尖括号)

    因此,答案是,只有少数字符不能在二进制级别使用。首先,
    /
    是包分隔符。然后,
    [
    不能使用,因为它们在和中具有特殊含义,可能包含类型名。在这些签名中,
    [
    启动一个数组类型,并
    标记引用类型名称的结尾

    没有明确的理由禁止使用
    。它不在JVM中使用,只在中有意义,但如果您使用的是泛型签名,则类型名将进一步受到限制,不允许包含
    ,并且这些字符在泛型签名中也有特殊意义

    因此,在标识符中使用
    违反规范对JVM的主要功能没有影响。有混淆器这样做。产生的代码可以工作,但在请求泛型类型签名时可能会遇到反射问题。此外,通过替换所有将二进制名称转换为源名称e> 如果二进制名称包含
    s,则带有
    s的/
    s将变得不可逆


    可能有一点很有趣(参见第3点“外来标识符”),但它并没有进入最终的Java7。而且,似乎目前还没有人尝试引入它


    还有一个附加的技术限制,即名称不能有更长的长度
    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