[ダイナミックエージェント三部作:中]-ダイナミックエージェントからClassファイル構造定義を参照


前言


この内容は前の[ダイナミックエージェント三部作:上]-ダイナミックエージェントがどのように「穴が落ちた」のか、4500元の補充で、さらに分析編です.両者を組み合わせて食べることを提案して、アルコールの香りは柔らかくて、口の中ですぐ溶けます.
さあ、いい加減にしないで、始めましょう...

本文


2、Classファイルのフォーマット


ここはなぜ2から始まるのですか?前の文章は1だから
この部分の内容は皆さんがどのように感じているのか分かりません.最初に勉強したとき、私は霧の水で、どのように手をつけるか分かりませんでした.反射、JVMメモリモデル、クラスロードメカニズムを一歩一歩結合すると.振り返ってみると、一緒に広々としていることに気づきます.
この内容の最初に、私たちのdemoで使用されているクラス:RentHouseProcessorHandlerに基づいてこの問題を分析しましょう.このRentHouseProcessorHandlerを16進数エディタで開くとclassファイル:
正直この行の文字は、最初は断りました.ああ、神様、どうして私にこれらの幽霊を見せたの?実は私たちが心を静めて、高校時代に数学を勉強して、物理の公式のように真剣に対応したいと思っています.人為的に意味を定義した記号にすぎないことがわかります.
これらの16進数文字を読み取る準備をするときは、まず「Java仮想マシン仕様(Java SE 7)」のclassファイルの定義を見てみましょう.

2.1、Classファイルの規範構造


2.1.1、標準構造


上の図の内容は、実はとても分かりやすくて、よくない英語だからといって抵抗しないでください.それらを翻訳してみましょう:1、魔数;2、二次バージョン番号;3、主バージョン番号;4、定数プールの数量;5、定数プール;6、権限の識別;7、この類;8、親;9、インタフェースの数;10、インタフェース;11、変数の数;12、変数;13、方法の数;14、方法....
実は何かを発見したのではないでしょうか.これは一つの類が存在するべきものではないでしょうか.そうですね.Classファイルの構造は、私たちが作成したClassクラスに格納されているルールを固定しているだけです.最初の私は、奥深いと思って、彼らを理解する勇気がありませんでした.私がためらって、勇気を出して大いにやる準備をしていたとき、やっとそれが簡単すぎることに気づいた...いくつかのルールです.それだけです.

2.1.2、特に注意する構造:表


いくつかのルールですが、ルールの中には、特に注意しなければならない点があります.例えばcp_infoというタイプです.『Java仮想マシンを深く理解する』では、著者はinfoの末尾のタイプを「テーブル」と呼びます.ここでは、このような表現に沿ってみましょう.はっきり言って、それはマルチレベルの関係を持つタイプです.
cp_infoは定数プールを表します(定数プール:まず、メソッド領域で実行される定数プールとは同じ内容ではありません.ここで、定数プールには字面量と記号参照が格納されています).

シンボル参照:


シンボル参照:
  • クラスおよびインタフェースのグローバル限定名
  • フィールドの名前と記述子
  • メソッドの名前と記述子
  • ここで記号の引用の役割は、まず一つの問題にしたいと思います.CPUがプログラムを実行するときは,実際には対応命令のメモリアドレスを探す.しかし、私たちのClassファイルは先にコンパイルされていますが、この時点ではJVMにメモリにロードされていないので、メモリアドレスは存在しないに違いありません.したがって、Classファイルには、JVMがコンテンツをロードするときに定数プールから対応するシンボルリファレンスを取得し、特定のメモリアドレスにマッピングする識別情報が必要です.
    定数プールに格納された中データ項目は、Java仮想マシン仕様(Java SE 7)に14個の定数があり、各定数は「テーブル」であり、各定数は共通のtagで表されます.具体的な内容は以下の図である.
    ここではまずこの定数プールを解読してみましょう.u 4の魔数、u 2のこのバージョン、u 2のメインバージョンをスキップしましょう.直接constant_を見てみましょうpool_count.対応する内容をスキップすると、私たちのconstant_pool_countは16進数の20に対応し、10進数の32に対応しています.つまり、定数プールには32の内容がありますか.実際にはそうではありません.設計者が0番目の位置を空けて別の計画をしているからです.だから私たちの定数プールには31の内容しかありません.
    javapコマンドでこの問題を確認できます.
    次のバイト:0 a、10進数に訳すと10で、私たちの表のCONSTANTに対応します.Methodref_info、次の4バイト.インデックス3,20をそれぞれ表します.ここのインデックスはどういう意味ですか?注意下図で落札された赤い箇所を理解する:
    次に、これらの内容を一つ一つ解読しません.それは対応する過程だからです.仲間たちが興味があれば、自分で解読してみてくださいね.JavaClassViewerツールをお勧めします.これらのコンテンツを簡単に表示できます.
    定数プールが終わった後、私たちの正常な変数、方法の情報です.ここでは、記述子という新しい概念を理解する必要があります.私たちにとって変数、方法がjavaソースコードの中でどのようになっているかはよく知っています.しかし、classファイルではどのようなものですか?この様子は実は「記述子」と呼ばれています.
    動的エージェントについて上述したとき、ProxyGenerator.generateProxyClass(proxyName,interfaces, accessFlags);の方法のうち、
    dout.writeInt(0xCAFEBABE);
    MethodInfo minfo = new MethodInfo("", "(Ljava/lang/reflect/InvocationHandler;)V",ACC_PUBLIC);    

    などの方法で、私たちの$Proxy 0に必要なclass構造を構築しましたが、javapから出てきた内容と似ていますか?次に記述子に入りましょう.

    2.2、変数、方法の記述子


    上記の内容の下敷きを経て、0 xCAFEBABEとはどういう意味なのか、言うまでもないはずです.<init>は構造方法の意味です.さらに(Ljava/lang/reflect/InvocationHandler;)VおよびACC_PUBLICはInvocationHandlerのpublicの構成方法として表すことができ、ここでVは戻り値がないことを表す.
  • <init>:オブジェクトコンストラクタメソッド.
  • <clinit>:クラスコンストラクタメソッド.

  • ここの内容は方法の記述子と呼ばれ、簡単に図を見て、この方面の内容を深めましょう.
    基本タイプとvoidは記述子に大文字と対応する.では、引用タイプの記述子は、どのようなものなのでしょうか.

    "L"+タイプのフルネーム+";"


    例えば以下の図:Ljava/lang/Object;つまり、これがObjectタイプであることを示します.
    メソッド記述子のルールも簡単です.上図では、まとめて一言です.

    (パラメータタイプ1パラメータタイプ2パラメータタイプ3...)戻り値のタイプ


    例えば、上の図の:int[]m(int i,String s)を記述子に変換する:(ILjava/lang/String;)[I
    こんなにたくさんの図を切ったのに、記述子について明確な認識があるかどうか分かりません.はっきり言って、私たちのProxyGenerator.generateProxyClass(proxyName,interfaces, accessFlags);のwriteの内容は具体的な方法の記述子です.
    そしてDataOutputStreamからbyte配列に移行すると、私たちのClassファイルに固定されている内容になります.そのため、Classファイルはすでに構築されており、次にメモリにロードして使用する必要があります.

    2.3、終了


    ここでclassファイル構造の内容を終了する準備をします.仲間たちが収穫があるかどうか分からない.紙幅が限られているので、一部の内容は一言でははっきり説明できない.だから一部の内容を持ってきて、本当に申し訳ありません.詳細については、「Java仮想マシンの理解」を参照してください.
    ご了承ください.