[Javaノート]リフレクションメカニズム

概要:

動的言語:

実行時に構造を変更できる言語のクラス。たとえば、新しい関数、オブジェクト、およびコードを導入したり、既存の関数を削除したり、その他の構造を変更したりできます。

静的言語:

実行時構造が不変である言語は静的言語です。

Javaは動的言語ではありませんが、準動的言語と言えます。つまり、Javaには動的な性質があり、リフレクションメカニズムを使用して動的言語と同様の特性を得ることができます。


リフレクションメカニズム:Javaリフレクション。プログラムが実行中にReflectionAPIを使用して任意のクラスの内部情報を取得できるようにし、任意のオブジェクトの内部プロパティメソッドを直接操作できるようにします

クラスがロードされた後、ヒープメモリのメソッド領域にクラスタイプのオブジェクトが生成され(クラスにはクラスオブジェクトが1つだけあります)、このオブジェクトにはクラスの完全な構造情報が含まれています このオブジェクトを通してクラスの構造を見ることができます。このオブジェクトは鏡のようなもので、クラスの構造を見ることができるため、画像は反射と呼ばれます。

反射の利点:

動的なオブジェクトの作成とコンパイルを柔軟に実現できます

リフレクションのデメリット:

パフォーマンスに影響します。


リフレクション関連のAPI:

java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Construtor:代表类的构造器

 

 

  クラスのメモリにはクラスオブジェクトが1つだけあります

クラスがロードされた後、クラスの構造全体がClassオブジェクトにカプセル化されます

 クラスクラス:

Class getclass()メソッドはObjectクラスで定義されており、このメソッドはすべてのサブクラスに継承されます

クラスごとに、JREはそのために不変のクラス型オブジェクトを予約し、クラス型オブジェクトには特定の構造が含まれます

●クラス自体もクラスです

●クラスオブジェクトは、システムでのみ作成できます

●ロードには、JVM内のクラスのインスタンスが1つだけあります

Classオブジェクトは、JVMにロードされた.classファイルに対応します

クラスの各インスタンスは、それが生成されたクラスインスタンスを記憶します

●クラスを通じて、クラスのすべてのロードされた構造を完全に取得できます

ClassクラスはReflectionのルートです。動的にロードして実行するクラスの場合、最初に対応するClassオブジェクトを取得する必要があります。

Classクラスのインスタンスを取得します。

特定のクラスがわかっている場合は、セキュリティと信頼性の高いクラスのクラス属性から取得できます。

Class c=Person.class;

クラスのインスタンスがわかっている場合は、インスタンスのgetClass()メソッドを呼び出して、Classオブジェクトを取得します。

Class c=person.getClass();

クラスの完全なクラス名は既知であり、クラスはクラスパスにあります。これは、Classクラスの静的メソッドforName()を介して取得でき、ClassNotFoundExceptionをスローする可能性があります。

Class c=Class.forName("路径/类名")

 

        Person person=new Student();
        //通过对象获得
        Class c1=person.getClass();
        //通过forname获得
        Class c2=Class.forName("Reflection.Student");
        //通过类名.class获得
        Class c3=Student.class;
   ------------------------------------------------------

        //基本内置类型的包装类都有一个TYPE属性
        Class c4=Integer.TYPE;
        System.out.println(c4.hashCode());
        //获得父类类型Person
        Class c5=c1.getSuperclass();

どのタイプがClassオブジェクトを持つことができますか?

クラス:外部クラス、メンバー内部クラス、静的内部クラス、ローカル内部クラス、匿名内部クラス

インターフェイス:インターフェイス

[]: 配列

列挙型:列挙 

注釈:注釈

プリミティブ型:基本データ型

空所

要素タイプがディメンションと同じである限り、それはクラスです 

JAVAメモリ分析:

クラスのロードとClassLoaderの理解:

ロード:

クラスファイルのバイトコードコンテンツをメモリにロードし、これらの静的データをメソッド領域のランタイムデータ構造に変換します

次に、このクラスを表すjava.lang.Classオブジェクトを生成します

リンク:

JavaクラスのバイナリコードをJVMの実行状態に組み込むプロセス

検証:ロードされたクラスがJVM仕様に準拠し、セキュリティ上の懸念がないことを確認します

準備:クラストラバーサル(静的)にメモリを正式に割り当て、メソッド領域に割り当てられるクラス変数のデフォルトの初期値を設定する段階

解決策:仮想マシンの定数プールのシンボリック参照(定数名)を直接参照(アドレス)に置き換えるプロセス

初期化:

クラスコンストラクター<clinit>()メソッドを実行するプロセス。クラスコンストラクター<clinit>()メソッドは、コンパイル時にクラス内のすべてのクラス変数の割り当てを自動的に収集し、静的コードブロック内のステートメントを組み合わせることによって生成されます。(クラスコンストラクターはクラス情報を構築するためのものであり、このクラスのオブジェクトを構築するためのコンストラクターではありません)

クラスを初期化するときに、その親クラスが初期化されていないことがわかった場合は、最初にその親クラスの初期化をトリガーする必要があります

仮想マシンは、クラス<clinit>()メソッドがマルチスレッド環境で適切にロックおよび同期されることを保証します。

   クラスのアクティブな参照(クラスの初期化が発生する必要があります)
➢仮想マシンが起動したら、メインメソッドが配置されているクラスを初期化します➢
クラスの新しいオブジェクト
➢静的メンバー(最終定数を除く)とクラスの静的メソッドを呼び出します
➢javaを使用します.lang .reflectパッケージのメソッドは、クラスをリフレクション呼び出しします
➢クラスが初期化されるとき、その親クラスが初期化されていない場合、その親クラス
   のパッシブ参照が最初に初期化されます(クラスの初期化は発生しません)
➢静的ドメインにアクセスする場合、実際にフィールドを宣言するクラスのみが初期化されます。例:親クラスの静的変数がサブクラスを介して参照される場合、サブクラスの初期化は発生しません
。➢配列を介してクラス参照を定義しても、
このクラスの初期化はトリガーされません。呼び出しクラス)

クラスローダー:

➢クラスロードの役割:クラスファイルのバイトコードコンテンツをメモリにロードし、これらの静的データを
メソッド領域のランタイムデータ構造に変換してから、ヒープ内でこのクラスを表すjava.lang.Classオブジェクトを次のように生成します。メソッド領域のクラスデータへのアクセス
エントリ。
➢クラスキャッシュ:標準のJavaSEクラスローダーはオンデマンドでクラスを検索できますが、クラスがクラスローダーにロードされると
、一定期間ロード(キャッシュ)されたままになります。ただし、JVMガベージコレクションメカニズムはこれらのクラスオブジェクトをリサイクルできます
 

クラス情報を取得する:

        Class c1=Class.forName("Reflection.User");
        //获得类的名字
        System.out.println(c1.getName());//获得包名+类名
        System.out.println(c1.getSimpleName());//获得类名
        //获得类的属性
        Field[]field11=c1.getFields();//获取Public属性
        Field[]fields=c1.getDeclaredFields();//获取全部属性
        //获取指定属性的值
        Field name=c1.getDeclaredField("name");
        //获得类的方法
        Method[]methods=c1.getMethods();//获得本类及其父类的全部Public方法
        methods=c1.getDeclaredMethods();
        //获取类的指定方法
        //需要传入参数类型
        Method getName=c1.getMethod("getName",null);
        Method setName=c1.getMethod("setName",String.class);
        //获取构造器
        Constructor[] constructors = c1.getConstructors();
        constructors=c1.getDeclaredConstructors();
        //获取指定的构造器
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class,int.class,int.class);

リフレクションを介して動的にオブジェクトを作成する

       //通过构造器创建对象
        Class c1=Class.forName("Reflection.User");
        //获取构造器后newInstance
        User user=(User) 
      c1.getDeclaredConstructor(String.class,int.class,int.class).newInstance("李",001,18);
        System.out.println(user);
        //通过反射调用方法:invoke
        c1.getDeclaredMethod("setName", String.class).invoke(user,"asd");
        //invoke:激活  (对象,方法的参数值)

        //通过反射操作属性

      Field name=c1.getDeclaredField("name");
      name.setAccessible(true);//设置私有成员的值时需要设置为true,否则访问不了

         name.set(user,"lll");

メソッドまたはフィールドがプライベートとして宣言されている場合は、メソッドを呼び出す前にsetAccessible(true)メソッドを明示的に呼び出して、プライベートメソッドにアクセスできるようにする必要があります。

setAccessible:アクセスセキュリティチェックを有効または無効にするように切り替えます

メソッド、フィールド、コンストラクターオブジェクトはすべてsetAccssible()メソッドを使用します

パラメータ値はtrueであり、反映されたオブジェクトが使用されたときにJava言語のアクセスチェックをキャンセルする必要があることを示します。

*コードでリフレクションを使用する必要があり、コードを頻繁に呼び出す必要がある場合は、trueに設定します

*他の方法ではアクセスできなかったプライベートメンバーにもアクセスできます

パラメータ値falseは、反映されたオブジェクトがJava言語アクセスチェックを実装する必要があることを示します

パフォーマンス分析:

 注釈を取得するための反射

        Class aClass = Class.forName("Reflection.Student1");
        //通过反射获得注解
        Annotation[] annotations = aClass.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);//@Reflection.Table("db_stu")
        }
        Table table=(Table)aClass.getAnnotation(Table.class);
        System.out.println(table.value());//db_stu

        //获得类指定的注解
        Field f=aClass.getDeclaredField("name");
        FieldTable annotation = f.getAnnotation(FieldTable.class);
        System.out.println(annotation);//@Reflection.FieldTable(colName="db_name", type="varchar", length=3)
        System.out.println(annotation.colName());// db_name
        System.out.println(annotation.type());//varchar
        System.out.println(annotation.length());//3

    }
}
@Table("db_stu")
class Student1{
    @FieldTable(colName = "db_id",type = "int",length =10)
    private int id;
    @FieldTable(colName = "db_age",type="int",length = 10)
    private int age;
    @FieldTable(colName = "db_name",type="varchar",length = 3)
    private String name;

    public Student1() {
    }

    public Student1(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
    String value();
}

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldTable{
    String colName();
    String type();
    int length();
}

おすすめ

転載: blog.csdn.net/m0_52043808/article/details/124076887