JVM - クラスクラスファイルの構造

あなたがコンパイル.javaファイルの.classファイルが疑問に思った後に生成されていない場合、私は知りません。

我々は、すべてのJavaは、JavaのクラスファイルにコンパイルするJavaコンパイラの経過後にクラスファイルの産物であることを知っています。私は、JavaでいくつかのCプログラマは、私はちょうど自分自身混乱も開始して、すべての点でおおよその.classファイルと同じに.outの生成されたファイルをコンパイルした後、認知考えでしょう大体Cプログラムで学習した後、あると思いますしかし、さらなる研究では、我々は何であるエンド内の.classファイルを把握する必要があります。

あなたはこのIDEA統合開発環境ツールでそれを見るために、ファイルを.classファイルならば、あなたはそれとソースコードを見つけるだろうし、それは仕方の.classファイルの逆コンパイルだったので、何の違いは、ありません。

異なるの.classファイルと.outのファイル

2つのファイルの違いを理解するために、我々は最初の二つの文書の定義を理解する必要があります。

.classファイル

JavaコンパイラJavaのクラスファイルをコンパイルし、バイナリバイトコードに翻訳元のテキストファイル(.javaファイル)、およびの.classファイルストアのバイトコードインチ

それぞれそのJavaクラスファイル属性、メソッド、および定数情報クラスは、.classファイルのファイルに保存されます。

この一節から、我々は我々の焦点を抽出:.classファイルがバイナリバイトコードです。JVMによって認識は、分析が行われます。

直接Javaのコード分析ツールと必要な基本的なスキルのセマンティック問題にバイトコードも作品を読むことができます。

.outファイル

ソースコード内の機械語命令を生成するコンパイラによってコンパイルされたC言語ソースコード(.Cファイル)、および.outのファイル(実行ファイル)に格納された記述情報を付加します。実行可能ファイルは、オペレーティングシステムをロードするために実行することができ、コンピュータは、ファイル内のマシン命令を実行します。

この一節から、我々は我々の焦点を抽出します.outのファイルはバイナリのマシン命令です。オペレーティングシステムによる実行がロードされます。

この時点で、既に明らか二つのファイルの差:まず、2バイナリファイルであるが、記憶装置は、バイトコード、マシン命令、全く異なるが。そして、異なるプラットフォームを実行して、1は、オペレーティングシステム、仮想マシンです。

.classファイルを意味

我々はすでに違いは何二つの文書の性質から知っているにもかかわらず、上記期間を理解しますが、使用時には、まだ何の違いも感じていない、両方の実行可能ファイルは、ああ、バイトコードと機械語命令です最後に、それはどのような違いを作るのですか?

起動時にコンピュータについての最初のレッスンから、先生は、私たちに言い続け、「コンピュータが唯一の束010101010101であるコンピュータ、その動作の性質上、内部のバイナリデータを認識し... ...」これはマシンの文字列010101です... ...オペレーティングシステムをロードできるように、コマンドは、.outをファイル上で実行されます。

それは何バイトコードですか?あなたはどこJavaの利点について考えることができ、このことについて考えてみてください。Javaコミュニティには、このような言葉の広がりは、ありません覚えておいてください「追記、どこでも実行します。」はい、バイトコードはプラットフォーム独立の基礎を提供することです。

Javaプログラムをバイトコードにコンパイルが、すべてが同じ生成され、バイトコードは、さまざまなプラットフォーム上で実行するJVMによってロードされます。ジャワのクロスプラットフォーム性を可能にするこの統一されたプログラム格納形式、。

その時点の方法は、今ますます開発者が高く評価している仮想マシンの他の大規模な中立的特性 - 他の言語のようなJavaプログラムを実行することができ、Java仮想マシンを持っているだけでなく、言語に依存しない、手段、JRubyの、Groovyの、などこれは、Java仮想マシン上で実行することができます。

全体的な構造の.classファイル

店舗内の特定のコンテンツの.classファイルを理解するために、我々はまず、全体的なストレージ・アーキテクチャの.classファイルの包括的な理解を持っている必要があります。もちろん、その前に、我々は最初の.classファイルの詳細な定義を作ります。

下に示し、具体的として独自の.classファイルへの任意のクラスまたはインタフェース対応:

クラスは、ベースユニットのバイト単位のバイナリ・ストリーム・ファイルのセット、クラスファイル内の各種データのコンパクトな配置です。そして、ビッグエンディアンモードと同様のデータ項目のストレージは、自分のBaiduのビッグエンディアンモードを理解していません。

符号なしの表:クラスファイルの構造は2つのデータ型が含まれています。それは複雑ではありません。

符号なしの数は、基本データ型は、我々はU1、U2、U4、U8は、それぞれ1バイト、2バイト、4バイト、8つのバイトを表しています。符号なしの番号は、図面、参照インデックス、UTF-8でエンコードされた文字列構成の値または番号を記述するために使用することができます。あなたは上記の単語を抽象化している場合は、ない心配を行い、最後を見に戻ってきて、あなた自身が解決されて不思議でしょう。

データ項目が「_info」端に慣れ構成として表符号なしの数が複数のテーブルまたは他の複雑なデータ構造です。クラスファイルは、基本的にテーブルです。
私たちはマジックナンバー、クラスファイルのバージョン、定数プール、クラスインデックス、親インデックス、インタフェースのインデックス集合、テーブル方式の設定テーブルのフィールドコレクション、プロパティシートのコレクションの重要な部分などのクラスファイルを理解することに焦点を当てる必要があります。テーブルのセットは、プロパティを説明するために、私は第二を配置します。

マジックナンバーとクラスファイルのバージョン

クラスファイルの構造と組成を学ぶためには、確かに、分析のためのクラスファイルを作成することを求めます。Javaコードのシンプルな作品を見て、それをコンパイル私たちは、それがこのコードの後に​​使用されていたであろうと、クラスが生成されたファイルなので、忘れなければ、過去に見ていない~~

パブリック クラスTestClassを{
     プライベート int型メートル。

    公共 int型INC(){
         戻り M + 1 
    } 
}

私たちは、Ubuntuの16.04でGHex16進テキストエディタを使用して表示するため、コンパイラによって生成されたファイルを.classファイル。図は次のとおりです。

 

マジックナンバーは、アクションは、仮想マシンがクラスファイルを受け入れることができるかどうかを決定するために各クラスファイルは、このファイルの最初の4バイトです。〜CAFEBABE(コーヒーの赤ちゃん?)、およびJavaロゴは、いくつかの接続を持っていると思われる。その値は、非常に簡単に覚えておくこともロマンがいっぱいです

そして、唯一のマジックナンバーは4に保存されているが、クラスファイルのバージョン番号をバイト:バイトのマイナーバージョン番号5,6、7,8バイトメジャーバージョン番号、一般的に可能にするために使用されるこれらの4バイトの役割を我々は現在のJDKバージョンを区別する、JDKの高いバージョンは、順番に、することはできません、以前のバージョンとの下位互換性があることができます。

一般的に、我々はあまりにもマイナーバージョン番号を心配する必要はありません、対応する変換のバージョン番号は、JDKの一般的な手順は次の通りです:

例えば、私のマイナーバージョン番号上の図は、メジャーバージョン番号は0x34の、8コンバート小数点52、JDKのバージョン52から45 + 1、、私の現在のJDKのバージョンJDK1.8ので、エラーなしで、0x00であります。

定数プール

どのようなクラスファイルの重要な部分は、私はそれは間違いなく定数プール(他のほとんどの項目に関連するデータの種類、最大クラスのファイル・スペース・データ項目、テーブル型データ項目の1つ)と、属性テーブル、プロパティシート上のセクションに属していると思う、と言うことです次回、私たちは話しています。

Java仮想マシンの実行時定数プールエリアの方法は、メモリへの.classファイルの後、クラスの定数プールをロードすることです。

定数プールカウント容量

定数プールは、代表的な定数プールカウント値の容量が、この値が設定されていないので、データの第1入射U2型(2バイト符号なし)であるため、定数プール内の固定された一定の数。あなたはこのクラスの定数プールファイルの容量を確認することができ、上記の画像から、0x0013です。

定数プールの容量が0から1の代わりに先頭からのカウント、クラスファイル容量で、それが唯一の定数プールが1で開始しているカウントされたことを言及する価値があります。この設計の目的は、特定の状況下で、「定数プール項目のいずれかを参照していない」の意味を表現する必要が背後にある特定のデータポイントのインデックス値の定数プールを満たすことです。

私のクラスファイルの定数プールの容量はわずか18定数、1から18までのインデックス値をある小数19に変換ようにします。

定数プール・ストレージ・プロジェクトの種類

容量を超える定数プールを言えば、我々はコンスタントプールに格納されたコンテンツを分析する前に、私たちがプレゼンテーションを行うために、ストレージタイプの定数プールを必要とし、定数プールの内容を分析する必要があります。

リテラルと記号参照:メインの定数プールは、2つの定数を保存します。

リテラル定数は、テキスト文字列、最終的に一定値などとして、Java言語レベルの概念があります。

(この後に記述の完全修飾名での)シンボル参照定数は以下の3種類:

javapコマンド

それは、今、効率重視の時代があり、安心仕事の後に私たちは、クラスファイルのバイトコードが枯渇することはないだろう読めば、と言われて、それがために使用されていないどのようなプログラマが1つの時代を穿刺するためのプログラムを書くために。

私たちは、コンピュータがしばしばてjavapコマンドスケール出力を意味使用することができます。

私たちは、使い方を見て:

// クラスTestClassをファイルには、私たちの上に生成されたTestClass.javaファイルの後にコンパイルされ 
てjavap -verbose TestClassを

定数プール以外の出力:(省略された情報を見てください)

クラスファイルは/ home / hg_yi /深入理解するJava虚拟机/类文件结构/ TestClassを。クラス
  最終更新日 2017年10月20日に、サイズ275 バイト
  MD5チェックサム4bb559d0c40918dfedd533c18bd75add 
  からコンパイルされた "TestClass.java"
 パブリック クラスTestClassをする
  :マイナーバージョン 0 
  メジャーバージョン: 52の
  旗:ACC_PUBLIC、ACC_SUPERの
定数プール: 1 = Methodref#4.#15          // 。のjava / LANG /オブジェクト」 <init> ":()V 
   #2 =するFieldRef#3.#16          // TestClass.m:I 
   #3 =クラス#17             // TestClassを
   #4 =クラス#18             // のJava /ラング/オブジェクト 
   #5 = UTF8 M  6 = UTF8 I  7 = UTF8 <初期化>  8 = UTF8()V  9 = UTF8コード 10 = UTF8 LineNumberTable  11 = UTF8 INC  12 = UTF8()I  13 = UTF8 SOURCEFILE  14 = UTF8 TestClass.java 15 = NameAndType#7:#8           // "<初期化>" :()V 
  #16 = NameAndType#5:#6           // M:I 
  #17 = UTF8 TestClassを 18 = UTF8のJava / LANG / オブジェクト

私たちは、参照されるべき多くのデータ項目が~~結果が戻って上記の出力に使用されますので、忘れないように、一定のクラスファイルの定数プールがあることを前に言いました

上記の出力は、多くの情報がクラスファイルを得られた結果の私たちの以前の分析と一致しているがあります。

1.マイナーバージョンとメジャーバージョン番号:

2.インデックス値の範囲:

 3.定数プール項目タイプ分析

コードは、アイテム4と15定数に第一の定常点を示しています。

java/lang/Object."<init>":()Vこの事、私たちはクラス記述子の完全修飾名については前にも言った、ちょっと待ってと言います。

アクセスフラグ

定数プール後、のみを含む、アクセスフラグは、クラスまたはインタフェースのレベル情報の一部を識別するために使用される2つのバイトを表す取る:ザ・クラスは、クラスまたはインタフェースであり、パブリック型として定義するかどうか、抽象型として定義されるかどうか、それがある場合クラス、finalとしてというように宣言されているかどうか。

次のように特定のフラグとその意味は以下のとおりです。

 通常てjavapコマンド上のスケールの構造を使用してコード、出力の行の後:

 0x0020に= 0x0021 | 0x0001に:私たちは、フラグの説明この種のが正しいことをアクセスフラグショーを見るため、その値access_flagsはする必要があります。あなたの元には、最​​上位のバイトコードに対応している場合、および2つのバイトは定数プールが一致した後に表示される値によって占められています。

クラスインデックス、インデックスの親クラス、インターフェイスインデックスセット

アクセスフラグの後、親クラスがクラスインデックスとインデックス、インタフェースインデックスのコレクションです。クラスインデックスは、インデックスは、データの親クラスU2型であり、インタフェースインデックスセットは、クラス3のデータファイルは、このクラスの継承を決定するためのデータ・タイプU2のグループです。

ヒント:Javaは単一継承され、およびJava Objectクラスのすべての親クラスを持っているので、java.lang.Objectの自体に加えて、その過剰オブジェクトに加えて、親インデックスJavaクラスはゼロとは異なります。

私たちは、最初の例を引き続き使用します:

マークされたバイトコード上の私の図は、一定のプール内の最初のインデックスの親定数の定数プール3、4で一定である0x0003,0x0004,0x0000、カテゴリインデックスです。ビット異なるインタフェースインデックス、インタフェースデータインターフェースカウンタの最初のインデックス-u2タイプは、インデックステーブルの容量を表します。私が言ったように、インデックステーブルに続くインターフェイスカウンタ値0は、もはやバイトインターフェイスを占めていると理解されていません。

 私達はちょうどてjavapコマンドの出力を組み合わせています:

  #3 =クラス#17             // TestClassを 
  #4 =クラス#18             // のJava /ラング/オブジェクト
 17 = UTF8 TestClassを 18 = UTF8のJava / LANG /オブジェクト

3,4定数は、それぞれ点17,18および定数を参照することができ、それらの値は、UTF-8フォーマットTestClassをおよびJava /ラング/オブジェクトです。

分析のこの部分は完了です。

テーブルのフィールドセット

テーブルの導入分野

このテーブルは、クラスまたはインタフェース内で宣言された変数を記述するために使用されます。

フィールドは、可変クラスレベル(静的)クラス及びインスタンス変数を含むが、ローカル変数を含んでいません。

フィールドには、どのような情報が含まれていますか?

スコープフィールド(パブリック、プライベート、保護された)、静的、最終的に、揮発性、過渡(シリアライズ)、フィールドのデータ型、フィールド名。

フィールドのデータ型に加えて、バイトの長さフィールド名は固定される必要はなく、定数プール基準コンテンツ、他の改質剤は、使用フラグビットのために適しています。

したがって、テーブルの主な分野には、以下の情報を記憶します。

など、追加情報のフィールドの後ろにattributes_info記載するために本明細書中で使用される:final static int m = 123;、テーブル123の一定の値にポイントフィールド一定値属性を有することになります。

その後、我々はと呼ばれるものを紹介する「単純名、完全修飾名、記述子。」

シンプル名、完全修飾名記述子

インデックス記述子インデックスの名前:私たちはテーブル構造内の他のデータフィールドを振り返ってみましょう。彼らは、カラムおよび方法と記述子の単純な名前を表す、定数プールへの参照です。

名前は、タイプおよびパラメータ修正方法またはフィールド名に単純ではない指し、このクラスの名前は、単にINCある()メソッドとMフィールド「INC」と「M」。

記述子は比較的複雑であり、我々は上に滞在問題という、記述子についてです。アクション記述子は、パラメータリストのデータタイプフィールド、および戻り値(数、タイプ、注文を含む)方法を説明するために使用されます。

基本データ型と空隙が資本文字で表され、オブジェクト型は、オブジェクトの文字プラスLの完全修飾名で表現されています

[Ljava」/:アレイタイプの場合、フロントの各次元に使用される「[」文字は、例えば、二次元アレイ「java.lang.Stringで[] []」型として記録さを定義し、説明しましたLANG /文字列;」、それはこれに来るとき、私は定義する表現の完全な名前を言及する必要があります。

名前の完全修飾名が示唆フルネームであるが、その表現や、完全修飾されたとして、我々は通常の書き込み何か違う、という名前の我々のテストクラスの先頭に「ORG / fenixsoft / clazz / TestClassを;」、それは完全な名前を入力することです「」 『/』に置き換えられ、最終的に追加して 『;』完全修飾名の終わりを示します。

記述子を使用

最初のパラメータリスト、戻り値。

あなたが理解していないとはどういう意味ですか?直接の例を見て:

無効株式会社()

Javaの.lang .String .toString()

INTのindexOf(CHAR []ソース、  INT sourceOffset、  INT sourceCount、  CHAR []ターゲット、  INT targetOffset、  INT targetCount、  INTたfromIndex)

実施例分析
クラスインデックスは、親インデックスフィールドは、インターフェースインデックステーブル後に設定され、それは、第1のタイプのデータU2容量カウンタfield_flagsあります。唯一のフィールドである0x0001という値は、次U2はaccess_flags符号...というように、固定データフィールドテーブルである上記チャートを示しから分析が完了する。

注:最後に、テーブルのフィールドのコレクションはリストが親クラスからフィールドから継承されていませんが、元のJavaコード内の列を一覧表示することがあり、外部クラスへのアクセスを維持するために、このような内部クラスのように、存在していない、意志自動的にクラスのインスタンスへの外部視野点を追加。

そこバイトコードは、のために二つのフィールドの説明はありません、重複した名前が合法であるというフィールドを変更した場合。このJava明らかに不可能です。

表収集方法

テーブルのフィールドとメソッドテーブルは、Iが所定のアクセス方法テーブルに署名ここに非常に類似しています。

 オリジナルリンク:https://blog.csdn.net/championhengyi/article/details/78300611

おすすめ

転載: www.cnblogs.com/blwy-zmh/p/11847859.html