Java のアノテーションとリフレクション (メモ)

1. 注意事項

1. アノテーションとは何ですか?

  • アノテーションはJDK5.0から導入された新しい技術です。
  • アノテーションの役割: それはプログラムそのものではなく、プログラムを説明することができます。他のプログラム(コンパイラなど)でも読み込むことができます。
  • アノテーション形式:アノテーションはコード内に存在する「@アノテーション名」であり、いくつかのパラメータ値を追加することもできます。

2. 組み込みの注釈

  • @Override: メソッド宣言がスーパークラス内の別の宣言をオーバーライドすることを意図していることを示すための品詞として使用されます。
  • @Deprecated: 非推奨ですが、使用できるか、より良い方法が存在します。
  • @SuppressWarnings: コンパイル中に警告メッセージを抑制するために使用され、パラメータを追加する必要があります。

//SuppressWarnings 用来抑制编译时的警告信息,必须要添加参数
@SuppressWarnings("all")
public class test1 extends parent{
    
    
    public static void main(String[] args) {
    
    
    }
    //Override 重写的注解
    @Override
    public void test1() {
    
    
        super.test1();
    }
    //Deprecated 不推荐使用,但是可以使用,或存在更好的方式。
    @Deprecated
    public static void test2(){
    
    
        System.out.println("这是Deprecated");}
}

3. メタ アノテーション
メタ アノテーションの役割は、他のアノテーションに注釈を付けることであり、Java では、
他のアノテーション タイプの説明を提供するために使用される 4 つの標準メタ アノテーション タイプが定義されています。

  • @Target: アノテーションの使用範囲を記述するために使用されます (つまり、記述されたアノテーションが使用できる場所)。
  • @Retention: アノテーション情報をどのレベルで保存する必要があるかを示し、アノテーションのライフサイクルを記述するために使用されます (SOURCE < CLASS < RUNTIME)
  • @Document: アノテーションが javadoc に含まれることを示します
  • @Inherited: サブクラスが親クラスからこのアノテーションを継承できることを示します
public class Test2 {
    
    
    @MyAnnotation
    public void test(){
    
    

    }
}

//定义一个自己的注解
//Target 表示这个注解可以用在哪个地方
//Retention 表示我们注解在什么地方有效
//Inherited 子类可以继承父类的注解
@Target(value = {
    
    ElementType.METHOD,ElementType.ANNOTATION_TYPE})
//runtime>class>source
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
@interface  MyAnnotation{
    
    

}

4. カスタム注釈

  • @interface カスタム アノテーションを使用する場合、java.lang.annotation.Annotation インターフェースが自動的に継承されます。
  • @interface は、注釈の宣言に使用されます。形式: public @interface 注釈名 {定義内容}。
  • これらの各メソッドは実際に構成パラメーターを宣言します。
  • メソッドの名前はパラメータの名前です。
  • 戻り値の型はパラメータの型です (戻り値は基本型、Class、String、enum のみです)。
  • パラメータのデフォルト値は、default を通じて宣言できます。
  • パラメーター メンバーが 1 つだけの場合、パラメーターには通常 value という名前が付けられます。
  • 注釈要素には値が必要です。注釈要素を定義するとき、デフォルト値として空の文字列と 0 を使用することがよくあります。
public class Test3 {
    
    
    //注解可以显示赋值,如果没有默认值,我们就必须给注解赋值。
    @MyAnnotation2(age=23)
    public void test1(){
    
    

    }

}
@Target({
    
    ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
    
    
    //注解的参数:参数类型+参数名();
    String name() default "";
    int age();

}

2. 反省

1. 反省とは何ですか?
リフレクションとは、コンパイル中にはまったく不明なクラスを実行時にロード、検出、使用できることを意味します。これは、プログラムのインスタンス化を指示し、属性を操作し、文字列を介してメソッドを呼び出すことを可能にする動的なメカニズムです。これによりコードの柔軟性が高まりますが、リソースのオーバーヘッドも増加します。
クラスがロードされると、ヒープ メモリに Class 型オブジェクトが生成されます (クラスには Class オブジェクトが 1 つだけあります)。このオブジェクトには、クラスの完全な構造情報が含まれています。このオブジェクトを通じてクラスの構造を確認できます。このオブジェクトは鏡のようなもので、それを通してクラスの構造を見ることができるため、私たちはそれを反射と呼んでいます。

2. 反映されたクラスを取得するにはどうすればよいですか?
まずUserエンティティクラスを作成します

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    
    
    private String id;
    public String name;
    private Integer age;
}

3つの方法で入手

//获取反射
public class Test1 {
    
    
    //通过Class.forName()获取(最常用)
    public static void main(String[] args) {
    
    
        try {
    
    
            Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        }
        //通过getClass()获取
        User  user = new User();
        Class aClass1 = user.getClass();

        //通过.class来获取
        Class<User> userClass = User.class;
    }
}

2. リフレクションをどのように使用するか?

  • クラス名、変数、フィールド、メソッドを取得する
public class Test2 {
    
    
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
    
    

        Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
        //获取全类名
        String name = aClass.getName();
        System.out.println(name);
        //获取简单类名
        String simpleName = aClass.getSimpleName();
        System.out.println(simpleName);
        //获取类的字段、某些变量
        //获取该类的所有public字段,包括父类的
        Field[] fields = aClass.getFields();
        for ( Field field: fields ){
    
    
            System.out.println(field.getName());
        }
        //根据字段名获取该类的public字段
        Field name1 = aClass.getField("name");
        //根据字段名获取该类的字段
        aClass.getDeclaredField("age");


    }
 Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
        //获取该类的所有public方法,包括父类的
        Method[] methods = aClass.getMethods();
        //根据方法名获取该类的public方法
        Method method = aClass.getMethod("getName");

        //如果该类为重写方法,可以在第二个参数加上重写方法的参数类型,不写为无参数的方法
        Method paramMethod = aClass.getMethod("getName",String.class);

        //获取该类的所有方法,不包括父类(仅自定义)
        Method[] declaredMethods = aClass.getDeclaredMethods();
        //根据方法名获取该类的方法
        Method declaredMethod = aClass.getDeclaredMethod("getName");
    }
  • クラスのコンストラクターを取得する
//获取类的构造器
public class Test4 {
    
    
    public static void main(String[] args) throws Exception {
    
    

        Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
        //获取该类的所有构造器,包括父类
        Constructor[] constructors = aClass.getConstructors();

        //根据构造器的参数类型来获取指定构造器,不写为无参构造器
        Constructor constructor = aClass.getConstructor();
        Constructor constructor1 = aClass.getConstructor(String.class,int.class);

        //获取该类的所有构造器,不包括父类
        Constructor[] declaredConstructors = aClass.getDeclaredConstructors();

        //根据构造器的参数类型来获取指定的自定义构造器,不写为无参构造器
        Constructor declaredConstructor = aClass.getDeclaredConstructor();
        Constructor declaredConstructor1 = aClass.getDeclaredConstructor(String.class, int.class);

    }
}
  • クラスをインスタンス化する
//类的实例化
public class Test5 {
    
    
    public static void main(String[] args) throws Exception {
    
    

        Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
        //通过class类直接实例化,使用的是User类的无参构造器
        User user = (User) aClass.newInstance();
        //获取构造器来进行实例化,这里获取有参构造器
        Constructor declaredConstructor = aClass.getDeclaredConstructor(String.class,String.class,Integer.class);
        //根据构造器进行实例化
        User user1 = (User) declaredConstructor.newInstance("12", "admin",44);
        System.out.println(user1);
    }
}
  • 演算結果

ここに画像の説明を挿入します

  • エミッションを使用してメソッドを呼び出す
public class Test6 {
    
    
    public static void main(String[] args) throws Exception{
    
    

        Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
        User user = (User) aClass.newInstance();
        Method setName = aClass.getMethod("setName", String.class);
        //第一个是调用底层方法的对象,也就是通过哪个对象来调用方法
        //第二个为可变参数,是用于方法调用的参数
        setName.invoke(user,"admin1");
        System.out.println(user);
    }
}
  • 演算結果
    ここに画像の説明を挿入します
  • リフレクションを使用してフィールドの値を変更します (セキュリティ チェックをスキップするには id.setAccessible(true) を使用します)
public class Test7 {
    
    
    public static void main(String[] args) throws Exception{
    
    
        Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");

        User o = (User) aClass.newInstance();
        Field id = aClass.getDeclaredField("id");
        //使用id.setAccessible(true)跳过安全检查
         id.setAccessible(true);
        //第一个参数为修改的字段的对象
        //第二个为被修改字段的新值
        id.set(o,"123");
        System.out.println(o);
    }
}
  • 演算結果
    ここに画像の説明を挿入します

3. アノテーションとリフレクションの使用

  • 注釈は以前に作成されたカスタム注釈です
//定义一个自己的注解
//Target 表示这个注解可以用在哪个地方
//Retention 表示我们注解在什么地方有效
//Inherited 子类可以继承父类的注解
@Target(value = {
    
    ElementType.METHOD,ElementType.ANNOTATION_TYPE})
//runtime>class>source
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
public @interface  MyAnnotation{
    
    
     String name() default "";
}
  • アノテーションの値を取得するには、まずリフレクションを使用してアノテーションによって変更されたクラスを取得し、次に ***getDeclaredAnnotation(アノテーション名.クラス)*** を呼び出してアノテーションの値を取得します。
//注解与反射
public class Test8 {
    
    

    public static void main(String[] args) throws Exception {
    
    
        Class aClass = Class.forName("com.example.dci.annotation.test1");
        Method test1 = aClass.getDeclaredMethod("test2");
        MyAnnotation declaredAnnotation = test1.getDeclaredAnnotation(MyAnnotation.class);
        String value = declaredAnnotation.name();
        System.out.println(value);


    }

}

おすすめ

転載: blog.csdn.net/lzfaq/article/details/122105249