JAva反射メカニズムは精巧で、乾物は見逃せない.

10073 ワード

JAva反射メカニズムの概要
ディレクトリ1.反射機構の概念2.反射のベースクラス3.反射の使い方4.反射の適用例
全桟学習ノート、努力している人
反射メカニズムの概念:
実行状態では、任意のクラスに対して、このクラスのすべての属性と方法を取得することができ、任意のオブジェクトに対して、プライベートな方法と属性を含む任意の方法と属性を呼び出すことができ、このような動的に取得された情報と動的にオブジェクトを呼び出す方法の機能をjava言語の反射メカニズムと呼ぶ.反射は動的言語の鍵と見なされます.簡単に言えば反射とはjavaの様々な成分が対応するjavaクラスにマッピングされることである.
一般的に言えば、反射を通じて、このクラスは私たちにとって完全に透明で、何でも手に入れたいと思っています.構築方法、属性、方法が含まれます.
JAva反射メカニズムが提供する機能:
実行時に任意のオブジェクトが属するクラスを判断する.実行時に任意のクラスのオブジェクトを構築します.実行時に任意のクラスが持つメンバー変数と方法を判断する.実行時に任意のオブジェクトを呼び出す方法.動的エージェントを生成します.
これは実際には言語の動的と静的にも関連しており、java言語自体は動的言語ではないが、彼は非常に際立った動的メカニズムを持っており、私たちが言っている反射メカニズムである.動的言語とは?つまり、プログラムが実行されている場合(実行時、コンパイル時ではないことに注意)は、プログラム構造や変数タイプを変更することを許可します.逆に静的ではないという特徴があります.
反射ベースクラス
Classクラスは反射実現の基礎であるため,反射を習得するにはClassクラスの基本的な概念を身につけなければならない.クラスは何ですか.クラスはクラスクラスのインスタンスオブジェクトなので、クラスはすべてのクラスのクラスです.
クラスを解剖するには、クラスのバイトコードファイルオブジェクトを取得する必要があります.解剖はClassクラスのメソッドを使用するので、まず各バイトコードファイルに対応するClassタイプのオブジェクトを取得します.
Classクラスには共通の構築方法はありません.Classオブジェクトは、クラスのロード時にJava仮想マシンおよび呼び出しクラスローダのdefineClassメソッドによって自動的に構築されるため、クラスオブジェクトを明示的に宣言することはできません.ここではまた、クラスのロードについて説明します.
簡単に説明します.
クラスローダ:プログラムがクラスを使用する必要がある場合、クラスがメモリにロードされていない場合、システムはロード、接続、初期化の3つのステップでクラスを初期化します.
≪ロード|Load|emdw≫:classファイルをメモリ(コンパイル後のファイルは.classファイル)に読み込み、クラスオブジェクトを作成するためにクラスが使用されると、システムはクラスオブジェクトを作成し、1回目はクラスが存在するかどうかを判断します.
接続:適切な内部構造があるかどうかを検証し、他のクラスと調整してクラスの静的メンバーにメモリを割り当てる準備をし、デフォルトの初期化値を設定し、クラスのバイナリデータの文字参照を直接参照に置き換える解析を行います.
Classオブジェクトは直接作成することはできませんが、他の方法でClassクラスを得ることができます.現在は3つの方法でClassクラスを得ることができ、Classクラスを得ると反射を正常に使用することができます.
クラスを取得する3つの方法(クラスのバイトコードオブジェクトを取得する):
1つ目:オブジェクト取得を使用し、オブジェクトのgetClass取得を使用する
Person person = new Person();
Class clazz = person.getClass();

2つ目:静的プロパティclassの使用
Class clazz = Person.class

3つ目:Classクラスの静的メソッドforName(文字列のクラス名)注を使用する;クラス名は全パッケージ名を書く
Class clazz = Calss.forName("…….");

さあ、ポイントが来ました.反射はどうやって遊ぶのが面白いですか.
反射の使い方
反射によって任意のクラスの何が得られるかという話をしましたが、本当かどうか見てみましょう.
最初のステップは何ですか?もちろんこれまでのどの3つの方法でこのやりたい放題のクラスを手に入れたのか.3つの方法があります.まず例を挙げましょう.じょうふごう
//  Class     
Student student = new Student();
Class clazz = student.getClass();
//  Class     
Class clazzTwo = Student.class;
//  Class     
Class clazzThree = Class.forName("demo.qzxxbj.entity.Student");

System.out.println("   "+clazz+"
"+clazzTwo+"
"+clazzThree);

結果
   class demo.qzxxbj.entity.Student
   class demo.qzxxbj.entity.Student
   class demo.qzxxbj.entity.Student

3つの方法で得られたClassオブジェクトは同じで,区別がないことがわかる.3つ目の方法は、クラスが見つからない異常が投げ出されることです.ここでStudentは単純なクラスであり、任意のクラスであってもよい.
クラスで任意のクラスの属性Studioクラスのコードを取得
package demo.qzxxbj.entity;

/**
 * @author wx:      
 * @date 2020/3/29
 * @description
 */

public class Student {
private String name;
private Integer age;
private String sex;
public int number;

public int getNumber() {
    return number;
}

public void setNumber(int number) {
    this.number = number;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Integer getAge() {
    return age;
}

public void setAge(Integer age) {
    this.age = age;
}

public String getSex() {
    return sex;
}

public void setSex(String sex) {
    this.sex = sex;
}

}
次のClassの取得方法は2つ目で、比較的簡潔です
	//  Class     
    Class clazzTwo = Student.class;

    //          public    ,     
    Field field = clazzTwo.getField("number");

    //field   public int demo.qzxxbj.entity.Student.number
    System.out.println("        public    ,     "+field);

    //             ,       
    Field deField = clazzTwo.getDeclaredField("name");

    // deField  private java.lang.String demo.qzxxbj.entity.Student.name
    System.out.println("         ,       "+deField);

    //       public       
    Field fields[] = clazzTwo.getFields();

    System.out.println("public     :");
    //public int demo.qzxxbj.entity.Student.number
    for (Field field1:fields){
        System.out.println(field1);
    }

    //            
    Field deFields[] = clazzTwo.getDeclaredFields();
    System.out.println("          ");
    //private java.lang.String demo.qzxxbj.entity.Student.name
    //private java.lang.Integer demo.qzxxbj.entity.Student.age
    //private java.lang.String demo.qzxxbj.entity.Student.sex
    //public int demo.qzxxbj.entity.Student.number
    for (Field field1:deFields){
        System.out.println(field1);
    }

getFields()、getField(String name)、getDeclaredFields()、getDeclaredField(String name)の違いを覚えておけば、この知識点をしっかり身につけることができます!
Classによる任意のメンバーの取得方法
やはりコードを見ましょう.
メンバーメソッドの取得Method
	//  Class     
    Class clazzTwo = Student.class;
    //             ,    public     ,     
    Method method = clazzTwo.getMethod("setAge",Integer.class);

    //public java.lang.Integer demo.qzxxbj.entity.Student.getAge()
    System.out.println(method);

    //                         ,      
    Method deMethod = clazzTwo.getDeclaredMethod("setAge", Integer.class);

    System.out.println(deMethod);

    //           public  ,     
    Method methods[] = clazzTwo.getMethods();

    //             ,          
    Method deMethods[] = clazzTwo.getDeclaredMethods();

Methodメソッドで印刷されるのは何ですか?上のコードにも含まれています
public void demo.qzxxbj.entity.Student.setAge(java.lang.Integer)

前に話したFieldと似ているのではないでしょうか.メソッドといえば、メソッド呼び出しにかかわるに違いありません.私たちはこれらのメソッドを得ました.このクラスのメソッドをどのように呼び出すべきですか.invoke関数を使うと、Methodというクラスにはinvoke関数が含まれています.英語が上手ならわかりますが、このinvokeの中国語の意味は「呼び出し」です.どのように使いますか.
    //  Class     
    Class clazzTwo = Student.class;
    //             ,    public     ,     
    Method method = clazzTwo.getMethod("setAge",Integer.class);

    //public java.lang.Integer demo.qzxxbj.entity.Student.getAge()
    System.out.println(method);

    //  Class         
    Student student = (Student) clazzTwo.newInstance();

    //    
    Object value = method.invoke(student,20);
    //null
    System.out.println(value);

以上のコードは、理解できないかもしれませんが、まず、クラスのクラスを取得し、このクラスのsetAgeメソッドを取得し、このメソッドを取得した後、このメソッドを呼び出し続けます.呼び出しメソッドはインスタンスオブジェクトのメソッドを呼び出すべきではありませんか.まずオブジェクトをインスタンス化する必要があります.どのような方法でclass内のnewInstance()を使用して、インスタンスを作成する必要があります.この方法では、インスタンス化されたクラスにパラメータなしの構築方法が必要です.インスタンスを作成する他の方法もありますが、後で説明します.インスタンスオブジェクトを作成すると、メソッドの呼び出しを開始できます.メソッドをinvokeで呼び出すと、invokeの最初のパラメータはインスタンス化オブジェクトです.そうしないと、私はどこでこのメソッドを探しますか.2番目のパラメータ、または3番目など、後のすべてのパラメータは私が呼び出したこのメソッドが持つパラメータで、順番に記入すればOKです.それからこの関数はObjectオブジェクトを返して、あなたはすべて考えることができて、私は1つの方法を呼び出して彼にいくつかの事をさせるかどうか、これらの事をして1つのものを返す必要があって、これが何なのか分からないで、Objectで取得します.私たちが呼び出したこの方法は値を返す必要がないのでnullです.簡単ですね.
Classによる構築方法の取得
これは私に最後に勉強させられました.結局、使う割合が少ないと思います.Classで構造方法を取得し、呼び出す方法を学びましょう.
public Student(String name, int id) {
    this.name = name;
    this.id = id;
}

ここではStudentクラスに構造方法を追加しました.
そして、この構造方法を取得します.
	//  Class     
    Class clazzTwo = Student.class;

    //        ,public   ,    ,                
    Constructor constructor = clazzTwo.getConstructor();

    //public demo.qzxxbj.entity.Student()
    System.out.println(constructor);

    //       public       
    Constructor constructors[] = clazzTwo.getConstructors();

    //           
    Constructor deConstructor = clazzTwo.getDeclaredConstructor(String.class,Integer.class);

    //            ,      
    Constructor deConstructors[] =clazzTwo.getDeclaredConstructors();

上のコードは分かりやすいでしょう.詳しくは言いません.ここでは、得られた構造方法をどのように使用するかについて説明します.構造方法は、その名の通りオブジェクトをインスタンス化します.Classでオブジェクトをインスタンス化する方法についても説明しましたが、ここでは、構造方法でオブジェクトをインスタンス化します.
	Student student = (Student) deConstructor.newInstance("      ",21);

    //21
    System.out.println(student.getAge());

今知っているでしょう.私たちは反射の機能を話し終わったのではないでしょうか.反射のダイナミックエージェントが1つ足りません.これは重要で、ブログを専門に出します.コードワードは容易ではありません.注目してほしい.
最後に私は自分の以前の経験に基づいてjava反射のsql文のつなぎ合わせを書いて、相当して1つの反射の応用でしょう.
反射の適用例
ダイナミックなSQL文を反射して生成するのも、ちょっとすごい感じではないでしょうか.直接コードに行きましょう、私はただ1つのSQL文だけを送って、興味のあるのは私に完全なコードを持ってもらうことができます!
public  String insert(Object object) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {`
    //insert into student(id,name,sex) values (1,"      "," ")
    StringBuilder sql = new StringBuilder();
    Class clazz = object.getClass();
    sql.append("insert into ");

    sql.append(clazz.getSimpleName()+"(");
    Field[] fields = clazz.getDeclaredFields();
    for(Field field:fields){
        sql.append(field.getName()+",");
    }
    sql.deleteCharAt(sql.length()-1);
    sql.append(")");
    sql.append(" values (");
    for(Field field:fields){
        field.setAccessible(true);
       Object value = field.get(object);

       String fieldName = field.getName();
       String str1 = fieldName.substring(0,1).toUpperCase();
       String str2 = fieldName.substring(1,fieldName.length());
       String strValue = str1.concat(str2);
		//String strValue = fieldName.substring(0,1).toUpperCase().concat(fieldName.substring(1,fieldName.length()));
       Method method = clazz.getMethod("get"+strValue,null);

       Object value1 = method.invoke(object,null);

//     if(value1.getClass().equals(String.class))
//     if(field.getType().equals(String.class))
        if(value1 instanceof String){
            sql.append("\"").append(value1).append("\"").append(",");
        }else {
            sql.append(value1).append(",");
        }
    }
    sql.deleteCharAt(sql.length()-1);
    sql.append(")");
    System.out.println(sql.toString());
    return sql.toString();
}

今期の説明はここまでで、後で注釈に関する文章も出るはずです.もし文章の中に間違いがあることに気づいたら、指摘してください.もしあなたが多くの知識を学ぶことができると思ったら、注目してください.転送を歓迎します!もっと多くの友达に学ばせます!