>  기사  >  Java  >  Java 클래스 파서를 구현하기 위한 강력한 코드 공유

Java 클래스 파서를 구현하기 위한 강력한 코드 공유

黄舟
黄舟원래의
2017-03-18 10:41:322531검색

저는 현재 ClassAnalyzer이라는 개인 프로젝트를 작성 중입니다. ClassAnalyzer의 목적은 <span class="wp_keywordlink">Java Class</span> 파일의 디자인과 구조에 대한 깊은 이해를 제공하는 것입니다. 본체프레임워크와 기본 기능은 완성되었으며, 향후 일부 세부 기능이 추가될 예정입니다. 사실 JDK은 이미 javap 파일을 디컴파일하는 명령줄 도구 Class를 제공하지만 이 글에서는 파서 구현에 대한 내 생각을 명확히 할 것입니다.

클래스 파일

은 클래스 또는 인터페이스 정보를 전달하는 역할을 합니다. 각 Class 파일은 클래스를 완전히 정의합니다. Java 프로그램을 "한 번 작성하면 어디서나 실행"할 수 있도록 Java 가상 머신 사양에는 Class 파일에 대한 엄격한 규정이 있습니다. Class 파일을 구성하는 기본 데이터 단위는 바이트입니다. 이로 인해 전체 Class 파일에 저장된 내용은 단일 바이트로 표현할 수 없는 거의 모든 데이터가 됩니다. . 데이터는 여러 연속 바이트로 표시됩니다.

Java 가상 머신 사양에 따르면 Class 파일은 C 언어 구조와 유사한 의사 구조를 사용하여 데이터를 저장합니다. 이 의사에는 두 가지 데이터 유형만 있습니다. -구조: 부호 없는 합계 테이블입니다. Java 가상 머신 사양은 u1 바이트, u2 바이트, u4 바이트 및 u8을 각각 나타내는 1, 2, 48을 정의합니다. . 부호 없는 숫자는 숫자, 색인참조, 수량 값 또는 문자열을 설명하는 데 사용할 수 있습니다. 테이블은 여러 개의 부호 없는 숫자 또는 기타 테이블을 데이터 항목으로 구성한 데이터 유형입니다. 테이블은 계층적 관계로 구조화된 데이터를 설명하는 데 사용되므로 전체 Class 파일은 기본적으로 테이블입니다. ClassAnalyzer에서 u1, u2, u4, u8는 각각 byte, short, int, long에 해당하며, Class 파일에 대해서는 다음과 같이 설명한다. 🎜> 친절해요. Java

public class ClassFile {

    public U4 magic;                            // magic
    public U2 minorVersion;                     // minor_version
    public U2 majorVersion;                     // major_version
    public U2 constantPoolCount;                // constant_pool_count
    public ConstantPoolInfo[] cpInfo;           // cp_info
    public U2 accessFlags;                      // access_flags
    public U2 thisClass;                        // this_class
    public U2 superClass;                       // super_class
    public U2 interfacesCount;                  // interfaces_count
    public U2[] interfaces;                     // interfaces
    public U2 fieldsCount;                      // fields_count
    public FieldInfo[] fields;                  // fields
    public U2 methodsCount;                     // methods_count
    public MethodInfo[] methods;                // methods
    public U2 attributesCount;                  // attributes_count
    public BasicAttributeInfo[] attributes;     // attributes

}

매직 넘버,

파일 버전 및 기타 데이터 항목, 액세스 플래그, 클래스 인덱스 등

파일을 구성하는

Class의 다양한 데이터 항목을 구문 분석하는 방법 , 부모 클래스 인덱스, 각 Class 파일에서 고정된 바이트 수를 차지하며 구문 분석 시 해당 바이트 수만 읽어야 합니다. 또한 유연하게 처리해야 하는 주요 부분으로는 Class 부분인 상수 풀, 필드 테이블 수집, 메소드 테이블 수집, 속성 테이블 수집이 있습니다. 필드와 메소드는 고유한 속성을 가질 수 있으며 4 자체에도 해당 속성이 있으므로 필드 테이블 컬렉션과 메소드 테이블 컬렉션을 구문 분석하면 속성 테이블도 구문 분석됩니다. Class

상수 풀은

파일의 데이터 중 많은 부분을 차지하며 숫자 및 문자열 상수, 클래스 이름, 인터페이스 이름, 필드 이름, 메소드 이름 등을 포함한 모든 상수 정보를 저장하는 데 사용됩니다. . Class가상 머신 사양은 여러 상수 유형을 정의하며, 각 상수 유형은 고유한 구조를 갖습니다. 상수 풀 자체는 테이블이며, 이를 구문 분석할 때 주의해야 할 몇 가지 사항이 있습니다. Java

  • 각 상수 유형은

    유형의 태그로 식별됩니다. u1

  • 헤더에 지정된 상수 풀 크기(

    )는 실제 constantPoolCount보다 큽니다. 예를 들어 1constantPoolCount과 같은 경우에는 항목 상수가 있습니다. 4746

  • 상수 풀의 인덱스 범위는
  • 부터 시작합니다. 예를 들어

    1과 같으면 상수 풀의 인덱스 범위는 . 디자이너는 "상수 풀 항목을 참조하지 않음"을 표현하기 위해 constantPoolCount 항목을 비워 두었습니다. 471~460

  • 유형 상수의 구조는
  • 유형의

    , CONSTANT_Utf8_info 유형의 u1을 포함하며 tag 유형의 u2개 조각으로 구성됩니다. length, 이 length바이트의 연속 데이터는 u1(bytes을 사용하여 인코딩된 문자열입니다. lengthMUTF-8과 호환되지 않습니다. 두 가지 주요 차이점이 있습니다. 첫째, Modified UTF-8) 문자는 MUTF-8 바이트(UTF-8null)로 인코딩됩니다. 둘째, 보조 문자는 2에 따라 서로게이트 쌍으로 분할되고 별도로 인코딩됩니다(변형 UTF-8). >

属性表用于描述某些场景专有的信息,Class文件、字段表和方法表都有相应的属性表集合。Java虚拟机规范定义了多种属性,ClassAnalyzer目前实现了对常用属性的解析。和常量类型的数据项不同,属性并没有一个tag来标识属性的类型,但是每个属性都包含有一个u2类型的attribute_name_indexattribute_name_index指向常量池中的一个CONSTANT_Utf8_info类型的常量,该常量包含着属性的名称。在解析属性时,ClassAnalyzer正是通过attribute_name_index指向的常量对应的属性名称来得知属性的类型。

字段表用于描述类或者接口中声明的变量,字段包括类级变量以及实例级变量。字段表的结构包含一个u2类型的access_flags、一个u2类型的name_index、一个u2类型的descriptor_index、一个u2类型的attributes_countattributes_countattribute_info类型的attributes。我们已经介绍了属性表的解析,attributes的解析方式与属性表的解析方式一致。

Class的文件方法表采用了和字段表相同的存储格式,只是access_flags对应的含义有所不同。方法表包含着一个重要的属性:Code属性。Code属性存储了Java代码编译成的字节码指令,在ClassAnalyzer中,Code对应的Java类如下所示(仅列出了类属性)。

public class Code extends BasicAttributeInfo {

    private short maxStack;
    private short maxLocals;
    private long codeLength;
    private byte[] code;
    private short exceptionTableLength;
    private ExceptionInfo[] exceptionTable;
    private short attributesCount;
    private BasicAttributeInfo[] attributes;
    ...

    private class ExceptionInfo {
        public short startPc;
        public short endPc;
        public short handlerPc;
        public short catchType;
          ...
    }
}

Code属性中,codeLengthcode分别用于存储字节码长度和字节码指令,每条指令即一个字节(u1类型)。在虚拟机执行时,通过读取code中的一个个字节码,并将字节码翻译成相应的指令。另外,虽然codeLength是一个u4类型的值,但是实际上一个方法不允许超过65535条字节码指令。

代码实现

ClassAnalyzer的源码已放在了GitHub上。在ClassAnalyzer的README中,我以一个类的Class文件为例,对该Class文件的每个字节进行了分析,希望对大家的理解有所帮助。

위 내용은 Java 클래스 파서를 구현하기 위한 강력한 코드 공유의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.