Program Club

Java 클래스 파일이 예약 된 키워드를 이름으로 사용할 수 있습니까?

proclub 2020. 12. 12. 11:38
반응형

Java 클래스 파일이 예약 된 키워드를 이름으로 사용할 수 있습니까?


Java-the-compilable-programming-language는 하나가 아니며 Java-the-bytecode-format-for-JVM-execution과 동일하다는 것을 알고 있습니다. 생성자가없는 클래스 및 합성 메소드와 같이 .class 형식에서는 유효하지만 .java 소스 코드에서는 유효하지 않은 것의 예가 있습니다.

  1. 우리가하면 손으로 공예의 .class 파일 예약 된 Java 언어 키워드 (예 :와 int, while클래스, 메소드 또는 필드 이름을), Java 가상 머신로드를 위해 그것을 받아 들일 것인가?

  2. 클래스가로드되면이 클래스 또는 멤버에 액세스하는 유일한 방법은 Java 프로그래밍 언어에서 구문 상 잘못된 이름이기 때문에 Java 리플렉션을 통해서만 액세스 할 수 있음을 의미합니까?


바이트 코드 수준에서 클래스 이름에 대한 유일한 제한은 그들이 문자를 포함 할 수 있습니다 [, .또는 ;그들이 가장에 걸 65535 바이트 길이. 무엇보다도 이것은 예약어, 공백, 특수 문자, 유니 코드 또는 개행과 같은 이상한 것들을 자유롭게 사용할 수 있음을 의미합니다.

이론적으로는 클래스 이름에 널 문자를 사용할 수도 있지만 파일 이름에 널 문자를 포함 할 수 없기 때문에 이러한 클래스 파일을 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

JVM 사양의 정확한 규칙 인용은 Holger의 답변참조하십시오 .


Yes, you can use reserved words. The words are only for the compiler. They do not appear in the generated byte code.

An example of using reserved Java words is in the JVM-based Scala language. Scala has different constructs and syntax than Java, but compiles to Java byte code, for running on a JVM.

This is legal Scala:

class `class`

This defines a class named class with a no-arg constructor. Running javap (a disassembler) on the compiled class.class file shows

public class class {
    public class();
}

Scala can do the same with any other Java reserved word.

class int
class `while`
class goto

They can also be used for method or field names.

As you suspected, you would not be able to use these classes from Java, except for reflection. You could use these from a similarly "customized" class file, e.g. from a class file generated by the Scala compiler.

In summary, this is a limitation of javac (the compiler), not java (the VM/runtime environment).


The restrictions about names are fixed in the JVM specification:

§4.2.1. Binary Class and Interface Names

Class and interface names that appear in class file structures are always represented in a fully qualified form known as binary names (JLS §13.1). Such names are always represented as CONSTANT_Utf8_info structures (§4.4.7) and thus may be drawn, where not further constrained, from the entire Unicode codespace…

For historical reasons, the syntax of binary names that appear in class file structures differs from the syntax of binary names documented in JLS §13.1. In this internal form, the ASCII periods (.) that normally separate the identifiers which make up the binary name are replaced by ASCII forward slashes (/). The identifiers themselves must be unqualified names (§4.2.2).  

§4.2.2. Unqualified Names

Names of methods, fields, local variables, and formal parameters are stored as unqualified names. An unqualified name must contain at least one Unicode code point and must not contain any of the ASCII characters . ; [ / (that is, period or semicolon or left square bracket or forward slash).

Method names are further constrained so that, with the exception of the special method names <init> and <clinit> (§2.9), they must not contain the ASCII characters < or > (that is, left angle bracket or right angle bracket).

So the answer is, there are only a few characters you can’t use on the binary level. First, / is the package separator. Then, ; and [ can’t be used because the have special meaning in field signatures and method signatures which may contain type names. In these signatures, [ starts an array type and ; marks the end of a reference type name.

There is no clear reason why . is forbidden. It isn’t used within the JVM and only has a meaning within generic signatures but if you are using generic signatures, the type names are further restricted by not being allowed to contain <, >, : as well as these characters have a special meaning within generic signatures too.

Consequently, violating the specification by using . within identifiers has no impact on the primary function of the JVM. There are obfuscators doing so. The resulting code works but you may encounter problems with Reflection when asking for Generic type signatures. Also, converting binary names to source name by replacing all /s with .s will become irreversible if the binary name contains .s.


It might be interesting that there was a proposal to support all possible identifiers within Java syntax (see point 3, “exotic identifiers”), but it didn’t make it into the final Java 7. And it seems, no-one is currently making a new attempt to bring it in.


There is the additional technical limitation that the names can’t have a Modified UTF-8 representation being longer than 65535 bytes because the number of bytes is stored as unsigned short value.


  1. Keywords are known only to the compiler. The compiler translates them into adequate bytecode. So they don't exist during runtime of compiled bytecode and, consequently, are not verified by the JVM.
  2. Surely, you can't access the class members that are not known at compile time. But you can use reflection for that purpose if you are sure that such class member will exist in the compiled code (you will "hand-craft" them there), because access by reflection is not verified by the compiler.

참고URL : https://stackoverflow.com/questions/30491035/can-java-class-files-use-reserved-keywords-as-names

반응형