マイクロチャンネル公衆番号へようこそ注意:BaronTalk、よりエキサイティングなグッドテキストを取得!
ASMクラス構造、方式記述子用にコンパイルされた文書を、読む前に、概念の多くは、フラグ、ACC_PUBLIC、ACC_PRIVATE、様々なバイトコード命令などの音が混乱、少し知識があるアクセス、その理由は、クラスファイルの構造にありますクラスローディング機構は理解されていません。それまでは明確な理解の設立前に、仮想マシンの実行サブシステム内の関連コンテンツ「Java仮想マシンの深い理解」を熟読。あなたは私のような場合は、クラスの構造とクラスのロードを理解していないが、仕事もバイトコードに関連するコンテンツが含まれ、私は2つの記事の後ろにあなたを助けると信じています。
私たちは、マシン上で実行するために書かれたコードの各行は、最終的に認識するためにマシンコードバイナリCPUにコンパイルする必要があります。しかし、仮想マシンの存在、オペレーティングシステムの違いを遮光し、このプログラミング言語の上に構築されたJava仮想マシンに似たCPUの命令セットは、通常、保存するために、中間ファイル形式にコンパイルされるまで、例えば、我々は今日お話したいと思いますバイトコード(バイトコード)ファイル。
I.言語の独立性
初期の設計上の考慮事項では、Java仮想マシンのデザイナーとJava仮想マシン上で実行されている他の言語の可能性を実現。だから、Java言語だけではなく、日付Kotlin、Groovyの、Jythonのは、そのようなJava仮想マシン上で実行するようにJVM言語のJRubyの数が多いため、Java仮想マシン上で実行することができます。そして、彼らは、バイトコードファイルにJava言語コンパイラと同じで、その後、仮想マシンで実行されます。クラスファイル(バイトコードファイル)は、言語に依存しないを持つようにします。
二つ。クラスファイルの構造
クラス・ファイルは、ファイル全体の内容を作る中間セパレータなしのコンパクトクラスファイルの順序に厳密に従って、それぞれのデータに基づいて、バイト単位で8ビットのバイナリストリームのセットは、クラスに格納されているほぼすべての手順であります実行に必要なデータは、隙間がありません。データ項目が8ビットバイトの上の空間を占有する必要があるためにそれが来るとき、貯蔵のために8ビット・バイトの複数にエンディアン方法を分割します。
クラスJava仮想マシン仕様ファイル形式は、データを格納するためにC言語の構造体と同様の微細構造を使用して、このようなダミー構造体は、データの2種類のみである:符号無しとテーブル。
-
符号なしの 1つのバイトを表すためにU1、U2、U4、U8に基本データ型に属し、符号なしの2バイト、4バイト、8バイト、符号なしの数を使用することができます図面、参照インデックス、そのUTF-8構造体の値または文字列の数の値を記載しました。
-
テーブルは、テーブルのデータ項目を構成として、複数の符号なしまたは他の複雑なデータ型で構成され、すべてのテーブルは、「終了」_info慣れています。階層データテーブルは、複合構造の関係を説明するために使用され、ファイル全体は、データ項目が設定以下の表に示すクラステーブルです。
タイプ | 名前 | 数量 |
---|---|---|
U4 | 魔法 | 1 |
U2 | minor_version | 1 |
U2 | major_version | 1 |
U2 | constant_pool_count | 1 |
cp_info | constant_pool | constant_pool_count-1 |
U2 | access_flags | 1 |
U2 | このクラス | 1 |
U2 | super_class | 1 |
U2 | interfaces_count | 1 |
U2 | インターフェース | interfaces_count |
U2 | fields_count | 1 |
field_info | フィールド | fields_count |
U2 | methods_count | 1 |
method_info | 方法 | methods_count |
U2 | attributes_count | 1 |
attribute_info | 属性 | attributes_count |
テーブルの上に、厳密な順序で保存されたクラスファイルバイトは、コンパクトに整列されます。バイト長は、すべての変更を許可していませんどのくらいの、順序が厳しく制限されているか、ある意味は何ですか。
マジックナンバーで2.1クラスファイルのバージョン
各ファイルのクラス最初の4つのバイトはマジックナンバー(マジックナンバー)と呼ばれ、その唯一の目的は、ファイルがCalss仮想マシンが受け取ることができるファイルであるかどうかを判断することです。ファイルの拡張子は変更して自由であるので、彼らは、主にセキュリティ上の考慮事項に基づいて識別されるファイル拡張子の代わりに魔法を使用しています。クラスファイルマジック値が「0xCAFEBABE」です。
4つのバイトが続くマジックナンバーは、文書クラスのバージョン番号で格納されている:5と6である全角マイナーバージョン番号(マイナーバージョン)、7及び8バイトはメジャーバージョン(メジャーであります版)。低クラスファイルのJDK後方互換性のあるバージョンの高いバージョン、クラスファイルのバージョン番号を超えて実行する仮想拒否。
2.2定数プール
メジャーバージョン番号は、定数プールエントリーされた後、定数プールは、ファイル・スペースがで、最大データクラスのプロジェクトの一つで占められている、データタイプの他のほとんどの項目に関連付けられたクラスファイル構造であるクラスファイル、間でリソースの倉庫として理解することができますそれはテーブル型データ項目またはクラスファイルが最初に表示されています。
定数プールが固定されていない定数の数は、それが「constant_pool_count」容量の定数プールを表すデータの定数プールエントリU2型内に配置する必要があり、コンピュータサイエンスのカウント方法は同じではないので、この容量は、1から開始されますむしろ、0からカウントを開始するよりも。うち最初の0一定の空気が特定のケースでは意味する「任意のプロジェクトに定数プールを参照していない」を表現する必要性の背後にある定数プールのインデックス値にデータポイントのいくつかを満たすために理由は、このインデックス値は次のように設定することができます0表現します。
クラスファイル構造のみ1から始まる定数プールカウント容量、およびインタフェースインデックスセット、テーブルのフィールドのセットを含むタイプの他のセット、メソッドテーブルは、ゼロから等量数を設定されています。
:定数の2種類格納するための主な定数プールリテラルとシンボル参照を。
-
リテラル文字列のような一定レベルのJava言語の概念に近いので、上の最後の一定値として宣言。
-
シンボル参照の概念は、次の3つの定数を含むビルドの原則局面に属しています:
- クラスやインタフェースの完全修飾名
- そして、記述子フィールド名
- メソッド名と記述子
2.3アクセスのロゴ
定数プールの後にアクセスフラグ(access_flag)を表す2つのバイトが続く、このフラグは、クラスのクラスまたはインタフェースを含むクラスまたはインタフェースレベルのアクセス情報の一部を識別するために使用され、公共のタイプとして定義されている場合、抽象型は次のように定義されているかどうか;それはそうで最終として宣言されているかどうか、ものの一種である場合。フラグと、以下の表中のフラグの特定の意味:
旗の名前 | フラグ値 | 意味 |
---|---|---|
ACC_PUBLIC | 0x0001 | 公共のタイプかどうか |
ACC_FINAL | 0x0010 | finalとして宣言されているかどうか、だけのクラスを設定することができます |
ACC_SUPER | 0x0020に | 新しいセマンティクスinvokespecialバイトコード命令の使用を許可するかどうか、セマンティックinvokespecial命令はJKD 1.0.2で変更されていた、セマンティクスを使用してこれらのマイクロチャット命令との違いは、このフラグのJDK 1.0.2コンパイルされたクラスが必要それは本当です |
ACC_INTERFACE | 0x0200 | これは、インタフェース識別子であります |
ACC_ABSTRACT | 0x0400 | 抽象型、または抽象クラスかどうか、他のクラスはFALSEで、このフラグのためのインタフェースが真であります |
ACC_SYNTHETIC | 0x1000番地 | このクラスは、ユーザーによって生成されたコードを識別しません |
ACC_ANNOTATION | 0x2000で | このロゴはコメントです |
ACC_ENUM | 0x4000の | このロゴは、列挙です |
16ビットフラグの合計access_flagsは現在わずか8れるのが定義され、使用されてもよい、フラグを使用する必要はない常に0です。
2.4カテゴリインデックス、および設定親クラスのインターフェイス・インデックスのインデックス
クラスインデックス(this_class)と親インデックス(super_class)U2は、データのタイプであり、インターフェースインデックスセット(インターフェース)はU2は、データ型の基である、クラスファイルがクラスによって決定された3つのデータを継承関係。
- クラスの完全修飾名を決定するためのクラスインデックス
- クラスの親クラスの完全修飾名を決定するための親のインデックス
- インターフェースインデックスセットは、このクラスは、インターフェイスを実装して記述するために使用されます
フィールド・テーブルは、2.5を設定しました
(field_info)設定フィールドテーブルは、クラスまたはインタフェース内で宣言された変数を記述するために使用されます。フィールド(フィールド)が、クラス、インスタンス変数を含むが、メソッド内で宣言されたローカル変数を含んでいません。ここでは、テーブルのフィールドの構造を見てみましょう。
タイプ | 名前 | 数量 |
---|---|---|
U2 | access_flag | 1 |
U2 | name_index | 1 |
U2 | descriptor_index | 1 |
U2 | attributes_count | 1 |
attribute_info | 属性 | attributes_count |
フィールドに修飾子をAccess_flags、それは非常によく似たクラスaccess_flag、U2はデータ型であるです。
旗の名前 | フラグ値 | 意味 |
---|---|---|
ACC_PUBLIC | 0x0001 | フィールドには、パブリックであるかどうか |
ACC_PRIVATE | 0×0002 | フィールドがプライベートであるかどうか |
ACC_PROTECTED | 0x0004は | フィールドが保護されているかどうか |
ACC_STATIC | 0x0008で | フィールドは静的であるかどうか |
ACC_FINAL | 0x0010 | フィールドがfinalであるかどうか |
ACC_VOLATILE | 0x0040が | フィールドが揮発性であるかどうか |
ACC_TRANSIENT | 0x0080 | フィールドは一時的なものであるかどうか |
ACC_SYNTHETIC | 0x1000番地 | フィールドが自動的にコンパイラによって生成されるかどうか |
ACC_ENUM | 0x4000の | フィールドが列挙されているかどうか |
テーブル2.6の設定方法
クラスファイルの記述及び方法の説明はまったく同じフィールドであり、テーブルのフィールドは、同じ工法のテーブルを持っています。
揮発性キーワードとキーワード過渡方法を修正することができないので、アクセスフラグテーブル法はACC_VOLATILEとACC_TRANSIENTないように。これとは対照的に、ネイティブ、strictfpのアブストラクトおよびキーワードは方法を変更することができる同期化し、アクセスフラグテーブル方式はACC_SYNCHRONIZED、ACC_NATIVE、ACC_STRICTFPとACC_ABSTRACTフラグを追加します。
コード内のメソッドのために内部の「コード」という名前のプロセス属性テーブルの属性に格納されて、コンパイルされたバイトコード命令にコンパイルされます。
2.7属性テーブルコレクション
自分の属性テーブル(attribute_info)クラスの文書コレクション、フィールドテーブル、メソッドテーブル、独自の特定のシナリオを記述した情報をもたらすことができます。
属性表集合不像 Class 文件中的其它数据项要求这么严格,不强制要求各属性表的顺序,并且只要不与已有属性名重复,任何人实现的编译器都可以向属性表中写入自己定义的属性信息,Java 虚拟机在运行时会略掉它不认识的属性。
写在最后
为了控制篇幅,这篇文章里丢弃了很多细节,比如常量池的项目类型、方法表、属性表的具体内容等等。建议想要深入了解的同学可以自己动手将 Java 类编译成二进制字节码文件,根据文章里介绍的类文件结构逐个字符去对照和实验,有助于加深理解。
关于「类文件结构」我们就介绍到这里,下一篇我们来聊聊「虚拟机的类加载机制」。
参考资料:
- 《深入理解 Java 虚拟机:JVM 高级特性与最佳实践(第 2 版)》
如果你喜欢我的文章,就关注下我的公众号 BaronTalk 、 知乎专栏 或者在 GitHub 上添个 Star 吧!
- 微信公众号:BaronTalk
- 知乎专栏:zhuanlan.zhihu.com/baron
- GitHub:github.com/BaronZ88