Java9之class文件格式變動

Java9之class文件格式變動

Java9已經於2017年09月27日發佈。Java9引入了很多新特性,其中最重要的特性,或者說最大的變化,無疑就是模塊化了。爲了支持模塊化,Java從方方面面都進行了改進,包括class文件格式。已經有很多文章介紹Java9模塊化,因此本文並不打算成爲另一篇模塊化入門文章。本文主要介紹Java9相較Java8在class文件格式方面的變動。


測試代碼

本文將基於模塊mymod進行討論,目錄結構如下所示:

j9cf
└── src
    └── mymod
        ├── a
        │   └── b
        │       ├── MyImpl.java
        │       ├── MyService.java
        │       └── c
        │           └── HelloWorld.java
        └── module-info.java

其中a.b包裏定義了MyServiceMyImpl兩個類,代碼如下所示:

package a.b;
public class MyService {}
package a.b;
public class MyImpl extends MyService {}

a.b.c包裏定義了HelloWorld主類,代碼如下所示:

package a.b.c;
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

module-info.java文件則對mymod模塊進行定義,代碼如下所示:

module mymod {
    requires java.base;
    requires static java.sql;
    requires transitive java.xml;
    exports a.b.c;
    exports a.b to java.sql, java.xml;
    opens a.b to java.sql, java.xml;
    uses a.b.MyService;
    provides a.b.MyService with a.b.MyImpl;
}

使用下面的命令對模塊進行編譯:

cd j9cf
path/to/java9/bin/javac \
    -d mods --module-source-path src \
    src/mymod/module-info.java \
    src/mymod/a/b/c/HelloWorld.java

使用下面的命令將模塊打包成jar格式:

cd j9cf
path/to/bin/jar --create \
    --file mymod-1.0.jar \
    --main-class a.b.c.HelloWorld \
    --module-version 1.0 \
    -C mods/mymod .

上面兩個命令執行完之後,j9cf目錄結構如下所示:

j9cf
├── mymod-1.0.jar
├── mods
│   └── mymod
│       ├── a
│       │   └── b
│       │       ├── MyImpl.class
│       │       ├── MyService.class
│       │       └── c
│       │           └── HelloWorld.class
│       └── module-info.class
└── src
    └── mymod
        ├── a
        │   └── b
        │       ├── MyImpl.java
        │       ├── MyService.java
        │       └── c
        │           └── HelloWorld.java
        └── module-info.java

class文件查看工具

Java自帶了命令行工具javap,可以反編譯並分析class文件格式。不過爲了更直觀的觀察class文件,本文使用圖形化工具classpy

class文件格式變動

class文件格式主要在四個方面有變動:版本號、類存取標誌、常量池、類屬性,下面分別進行介紹。

版本號

class文件大版本號由Java8的52(0x34)增加到了53(0x35),如下圖所示:
這裏寫圖片描述

類存取標誌

類的存取標誌(access_flags)新增加了ACC_MODULE(0x8000)標誌位,表示class文件描述的是一個模塊,如下所示:
這裏寫圖片描述

常量池

常量池增加了CONSTANT_Module_info和CONSTANT_Package_info兩種常量。

CONSTANT_Module_info

CONSTANT_Module_info的tag值是19,表示一個模塊,其結構如下所示:

CONSTANT_Module_info {
    u1 tag;
    u2 name_index;
}

比如mymod模塊module-info.class文件常量池的第15個常量就是一個CONSTANT_Module_info常量,表示mymod模塊自己,如下圖所示:
這裏寫圖片描述

CONSTANT_Package_info

CONSTANT_Package_info的tag值是20,表示模塊輸出(Export)或者打開(Open)的包,其結構和CONSTANT_Module_info一樣,如下所示:

CONSTANT_Package_info {
    u1 tag;
    u2 name_index;
}

比如mymod模塊module-info.class文件常量池的第7個常量就是一個CONSTANT_Package_info常量,表示a.b包,如下圖所示:
這裏寫圖片描述

類屬性

增加了三個預定義屬性:Module_attribute、ModulePackages_attribute和ModuleMainClass_attribute。

ModulePackages_attribute

ModulePackages_attribute屬性記錄和模塊相關(比如輸出或使用等)的包,結構如下所示:

ModulePackages_attribute {
    u2 attribute_name_index;
    u4 attribute_length;

    u2 package_count;
    u2 package_index[package_count];
}

其中package_index是個u2表,表裏的每個u2值都是常量池索引,並且索引指向的一定是CONSTANT_Package_info常量。mymod模塊module-info.class文件的ModulePackages_attribute屬性如下圖所示:
這裏寫圖片描述

ModuleMainClass_attribute

ModuleMainClass_attribute屬性記錄模塊主類,結構如下所示:

ModuleMainClass_attribute {
    u2 attribute_name_index;
    u4 attribute_length;

    u2 main_class_index;
}

其中main_class_index是指向CONSTANT_Class_info常量的索引。mymod模塊module-info.class文件的ModuleMainClass_attribute屬性如下圖所示:
這裏寫圖片描述

Module_attribute

Module_attribute屬性比較複雜,結構如下所示:

Module_attribute {
    u2 attribute_name_index;
    u4 attribute_length;

    u2 module_name_index;
    u2 module_flags;
    u2 module_version_index;

    u2 requires_count;
    {   u2 requires_index;
        u2 requires_flags;
        u2 requires_version_index;
    } requires[requires_count];

    u2 exports_count;
    {   u2 exports_index;
        u2 exports_flags;
        u2 exports_to_count;
        u2 exports_to_index[exports_to_count];
    } exports[exports_count];

    u2 opens_count;
    {   u2 opens_index;
        u2 opens_flags;
        u2 opens_to_count;
        u2 opens_to_index[opens_to_count];
    } opens[opens_count];

    u2 uses_count;
    u2 uses_index[uses_count];

    u2 provides_count;
    {   u2 provides_index;
        u2 provides_with_count;
        u2 provides_with_index[provides_with_count];
    } provides[provides_count];
}

Module_attribute屬性雖然結構複雜,但其實就是module-info.java文件中模塊定義裏requires、exports、opens、uses和provides語句的直接映射。mymod模塊module-info.class文件的Module_attribute屬性總體如下圖所示:
這裏寫圖片描述
requires語句對應的部分如下圖所示:
這裏寫圖片描述
exports語句對應的部分如下圖所示:
這裏寫圖片描述
opens語句對應的部分如下圖所示:
這裏寫圖片描述
uses語句對應的部分如下圖所示:
這裏寫圖片描述
provides語句對應的部分如下圖所示:
這裏寫圖片描述

廣告

以上Java9在class文件方面的變動就介紹完了,如果想深入瞭解Java8的class文件格式,請關注自己動手寫Java虛擬機 這本書 :)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章