熟練の深さへのエントリーからの反射クラスクラスを学びます

知っている、なぜ知っています

0.はじめに

この記事では、我々が反射のために知っていない場合は、私たちが見ることができ、反射の原理を説明します「0からのスタートに反映」、反射の大まかなアイデアを持っています、。

「マスターへのエントリからの反射は、」私が説明するために、2つに分割されます、これは説明することで、クラス Iは、反射を説明します隣に、クラスの原則をAPIの原則を。

原則1.クラスクラス

孟子は言った:誰が世界で人気。Javaでは、「心」はClassクラスに取得するクラス我々はそれが喜ばすものは何でもできるクラス。私たちの深い「人々は」Classクラスの原則を探求してみましょう。

まず、JVMのインスタンスを構築する方法を理解しています。

1.1 JVM構築物の例

JVM:Java仮想マシン、Java仮想マシン。JVMスタック、ヒープ、メソッド領域に、これらは、JVMを指す本明細書に記載されるように、RAMメモリJVMのメモリ。.classファイルはを通じて、ファイルのバイトコードであるの.javaファイルがコンパイルされてきます。

上記の内容を知って、私たちは、インスタンスを作成し始めました。私たちは、例えば、Personオブジェクトを作成する必要があります。

Person p = new Person()
复制代码

単純にすることで、新しいオブジェクトを作成するために、のようなそのプロセスは何ですか?下記を参照してください。

これは、それについてのその繊細で、いくつかの粗すぎます。

同志は決して、実際には、いくつかの違いがあることがわかっていない、私は違いがより上記より、次の言葉であなたを教え、あなたは(私の顔をヒットしていない)私にヒットしません。

それはによって荒れている新しいを通じて作成され、洗練されたオブジェクトのClassLoader。オペレーティングクラスファイルの生成クラスのクラス、およびそのオブジェクトを作成します。

実際には、経由新しいインスタンスまたは反射を作成するために、必要なクラスのオブジェクトを。

1.2の.classファイル

.class述べた資料の冒頭にファイルは、バイトコードファイルです。.javaソースプログラム。Javaは、ソースファイルからコンパイルクロスプラットフォームのプログラム、どこでもコンパイラの実装は、バイトコードファイルに変換されています。

0と1以上のものからなるバイトコード。

以下のクラス:

vimの表情バイトコードファイルで:

これは地獄で、私は読むことができません。あなたはとにかく、理解する必要はありませんJVMのための.classは、ファイルを読むために独自のルールを持っています。

1.3クラスローダ

上記の絶妙な景色を忘れないでください、私たちは、クラスローダであることを知っているの.classファイルメモリにロードされます。特定のクラスローダの内容、私は(リンクはここで更新されます完了するために)説明するために、別の記事を書きます。コアはloadClass()にある。しかし、唯一のあなたがロードするように指示する必要がある名前を、それが負荷にお手伝いを致します。

protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        // 1.检查类是否已经加载
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                // 2.尚未加载,遵循父优先的等级加载机制(双亲委派机制)
                if (parent != null) {
                    c = parent.loadClass(name, false);
                } else {
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }

            if (c == null) {
                // 3.如果还没有加载成功,调用 findClass()
                long t1 = System.nanoTime();
                c = findClass(name);

                // this is the defining class loader; record the stats
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

// 需要重写该方法,默认就是抛出异常
protected Class<?> findClass(String name) throws ClassNotFoundException {
    throw new ClassNotFoundException(name);
}
复制代码

クラスローダがロードの.classファイルには、以下の3つのステップに分けています

  1. クラスがすでにロードされている場合は、直接のリターンがあるかどうか、確認してください
  2. このクラスは、現在存在し、負荷に両親デリゲートメカニズムに従っていません。クラスファイルを
  3. 他のすべて上記の二つのステップが失敗し、()を呼び出すにfindClass

findClassクラスローダメソッドが例外をスローしているので、我々はそれのようなデフォルトのサブクラスをカバーするために再書き込みする必要があります。

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            // 通过IO流从指定位置读取xxx.class文件得到字节数组
            byte[] datas = getClassData(name);
            if (null == datas){
                throw new ClassNotFoundException("类没有找到:" + name);
            }
            // 调用类加载器本身的defineClass()方法,由字节码得到 class 对象
            return defineClass(name, datas, 0, datas.length);
        }catch (IOException e){
            throw new ClassNotFoundException("类没有找到:" + name);
        }
    }

    private byte[] getClassData(String name) {
        return byte[] datas;
    }
复制代码

クラスdefineClassは、バイトコードの方法により取得されたクラスローダに定義されています。具体的には、我々は最終的にネイティブメソッドを呼び出すため、達成する方法がわかりません。

    private native Class<?> defineClass0(String name, byte[] b, int off, int len,
                                         ProtectionDomain pd);

    private native Class<?> defineClass1(String name, byte[] b, int off, int len,
                                         ProtectionDomain pd, String source);

    private native Class<?> defineClass2(String name, java.nio.ByteBuffer b,
                                         int off, int len, ProtectionDomain pd,
                                         String source);
复制代码

クラスローダの負荷をまとめる。クラスのステップのファイルを:

  • クラスローダクラスのloadClass()メソッドは、取得するクラス
    • キャッシュを検索し、直接リターン
    • それは両親によって任命されたキャッシュ、ローディング機構には存在しません。
    • 他のすべて上記の二つのステップが失敗し、呼び出しにfindClassを)(
      • 流れるようにIOによって指定された場所から取得された。クラス取得したファイルのバイト配列
      • クラスローダは、呼び出しdefineClassバイトの配列から得られた()メソッドは、クラスのオブジェクトを

1.4 Classクラス

.classファイルは、メモリクラスローダにロードされ、バイト配列を生成された、JVMは、に従って、対応するバイト配列の作成クラスのオブジェクトを。

次は、私たちは分析する必要があるクラスのオブジェクトを。

私たちは、Javaオブジェクトには、以下の情報を持っていることを知っています:

  1. 権限の修飾子
  2. クラス名と一般的な情報
  3. インターフェース
  4. エンティティ
  5. コメント
  6. コンストラクタ
  7. 方法

この情報。クラス 0101のファイルは、最後のJVMがすると発表した.classファイルを経由して、それに保存された情報ファイルクラスでは。

ではクラス確かフィールドは、この情報を保持している、我々は見て:

クラスクラスによってReflectionDataフィールドおよび内部の.classコンテンツマッピング、マップされたフィールド、メソッド、インターフェイスコンフィギュレーション。

annotaionData、他のはあなた自身を開くことができ、表示されていないアノテーションデータをマッピングされたIDEAのビュークラスのソース。

その後、我々は見てクラスのクラスのメソッド

1.4.1コンストラクタ

クラスクラスのコンストラクタは介してのみ、プライベートでJVM作成クラスオブジェクト。したがって、上記のクラスローダによってそこに取得されるクラスのプロセスオブジェクト。

1.4.2 Class.forNameの

Class.forNameの()メソッドは、クラスローダによって取得されたクラスオブジェクト。

1.4.3のnewInstance

newInstance()基本となる非戻り引数のコンストラクタ。

2.概要

私たちは、以前の知識の下で整理する必要があります。

重要な点は、反射を取得することで、クラス、そのシステムをを取得する方法を、カテゴリをクラスクラス?

クラスローダによってクラスローダの.classファイルがにバイト配列の仕方によってロードされたJVMで、JVMはへのバイト配列に変換クラスオブジェクト。これは、クラスローダがそれをロードする方法ですか?

  • クラスローダはloadClass()メソッド
    • キャッシュを検索し、直接リターン
    • それは両親によって任命されたキャッシュ、ローディング機構には存在しません。
    • 他のすべて上記の二つのステップが失敗し、呼び出しにfindClassを)(
      • 流れるようにIOによって指定された場所から取得された。クラス取得したファイルのバイト配列
      • クラスローダは、呼び出しdefineClassバイトの配列から得られた()メソッドは、クラスのオブジェクトを

クラスクラスのコンストラクタはプライベートですので、必要であるJVMの取得クラス

Class.forNameの()はクラスローダによって取得されたクラスオブジェクト。newInstance根本的な方法は、また、引数のコンストラクタを返しません。


おすすめ

転載: juejin.im/post/5df8e473f265da33bc57df3e
おすすめ