Java でアノテーションとリフレクションを使用する方法

王林
リリース: 2023-05-10 14:04:06
転載
1251 人が閲覧しました

1. アノテーション

1.1 アノテーションとは

アノテーションはプログラムそのものではなく、プログラムのコンパイル時、クラスのロード時、実行時に読み込まれ、対応する処理を実行します。アノテーションの形式は「@アノテーション名(パラメータ値)」で、パッケージ、クラス、メソッド、フィールドに付加でき、リフレクション機構を通じてアクセスされます。

1.2 組み込みアノテーション

@オーバーライド: サブクラスによるメソッドのオーバーライドの制限

このアノテーションは、親クラスのメソッドがオーバーライドされることを示します。クラスが親クラスのメソッドをオーバーライドするときは、低レベルのエラーを回避するために、サブクラスが実際に親クラスのメソッドをオーバーライドしていることを確認してください

/**
 * 该注解标识覆盖的是其父类的方法,当子类重写父类方法时,确保子类确实重写了父类的方法,避免出现低级错误
 * @return
 */
@Override
public String toString() {
    return super.toString();
}
ログイン後にコピー

#@非推奨: マークは廃止されました #This 注釈は、プロパティ、メソッド、またはクラスが廃止されたことを示します (通常、危険であるか、より良い代替手段が存在するため、プログラマーが使用することを推奨されないプログラム要素)。他のプログラムが廃止されたプロパティ、メソッド、またはクラスを使用する場合と指定すると、コンパイラによって警告 (取り消し線) が表示されます。

/**
 * 该注解表示此方法已过时,存在危险,不推荐使用,其有代替方法,如果继续使用会通过删除线进行标识
 */
@Deprecated
public static void test() {
    System.out.println("标记已过时");
}
ログイン後にコピー

@SuppressWarnings (パラメータ): コンパイラ警告の抑制

このアノテーションの影響を受けるクラス、メソッド、およびプロパティは、コンパイラ警告の表示を抑制します。そのパラメータは次のとおりです。主に警告指示や解除(未チェック)など。

@SuppressWarnings("取消此类的所有警告")
public class BuiltAnnotation {
    
    @SuppressWarnings("取消此属性的警告")
    private String username;

    @SuppressWarnings("取消此方法的警告")
    public static void main(String[] args) {
        // ...
    }
}
ログイン後にコピー

1.3 メタ アノテーション (メタ アノテーション)

メタ アノテーションの役割は、他のアノテーションに注釈を付けることです。Java では 4 つの標準メタ アノテーション タイプが定義されており、これらは次のサポートを提供するために使用されます。他のアノテーション: スコープとタイプが記述されており、他のアノテーションはメタアノテーションを通じてカスタマイズできます。

@Target: アノテーションの使用範囲を記述します。

たとえば、@Target(ElementType.METHOD) は、@Target(ElementType) というメソッドに作用することを示します。 .TYPE) は、クラスやインターフェースなどに作用することを示します。

/**
 * @Target注解:描述注解的使用范围
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * 类或接口:ElementType.TYPE;
     * 字段:ElementType.FIELD;
     * 方法:ElementType.METHOD;
     * 构造方法:ElementType.CONSTRUCTOR;
     * 方法参数:ElementType.PARAMETER;
     * ...
     */
    ElementType[] value();
}
ログイン後にコピー

@Retention: アノテーション情報をどのレベルで保存する必要があるかを示し、アノテーションのライフサイクルを記述するために使用されます。

通常、カスタマイズされたアノテーションは、ランタイム効果である Use @Retention(RetentionPolicy.RUNTIME) です。

/**
 * @Retention:表示需要在什么级别保存该注解信息,用于描述注解的生命周期
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * RetentionPolicy.SOURCE:仅编译期,注解将被编译器丢弃。
     * RetentionPolicy.CLASS:仅class文件,注释将由编译器记录在类文件中,但VM不需要在运行时保留,如果不指定则默认为class。
     * RetentionPolicy.RUNTIME:运行期,注释将由编译器记录在类文件中,并由VM在运行时保留,因此可以反射读取。通常自定义的注解都是RUNTIME。
     * 范围:RUNTIME>CLASS>SOURCE
     */
    RetentionPolicy value();
}
ログイン後にコピー

#@Document: このアノテーションが javadoc に含まれることを示します。

@Iherited: サブクラスが親クラス定義を継承できるかどうかを定義するアノテーション。

@Inherited は @Target(ElementType.TYPE) 型の注釈にのみ役立ち、クラスの継承のみに使用でき、インターフェイスの継承には無効です:

1.4カスタム注釈

注釈の定義

/**
 * 1. 使用@interface定义注解;
 * 3. 通过元注解配置该注解,配置注解的使用范围和生命周期等
 * @author Loner
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Report{
    /**
     * 2. 添加参数、默认值,如果没有默认值,就必须给参数赋值,一般把最常用的参数定义为value(),推荐所有参数都尽量设置默认值
     * 形式为:参数类型 参数名();
     */
    int type() default 0;
    String value() default "LonerMJ";
}
ログイン後にコピー

注釈の使用

@Report(type = 1, value = "test")
public class CustomerAnnotation {
    @Report(type = 1, value = "test")
    public void testCustomerAnnotation() {
        System.out.println("测试自定义注解");
    }
}
ログイン後にコピー

2. リフレクション

2.1 リフレクションとリフレクションの仕組み

リフレクション

リフレクション (リフレクション) とは、プログラムが実行時にオブジェクトのすべての情報を取得できることを意味します。

リフレクション機構

リフレクション機構とは、プログラムの実行時に、リフレクション API を通じて任意のクラスのコンテンツ情報を取得し、内部のクラスを直接操作できることを意味します。任意のオブジェクトのプロパティとメソッド。

2.2 Class クラスと共通メソッドの取得方法

java.lang.Class クラスはリフレクションを実装するコアクラスであり、クラスがロードされるとクラスが生成されます。ヒープメモリのメソッド領域 Class オブジェクト (クラスには Class オブジェクトが 1 つだけあります)、このオブジェクトにはクラスの完全な構造情報が含まれており、クラスの構造はこのオブジェクトを通じて見ることができます。

#Class クラスの取得方法

public class InstantiationClass {
    public static void main(String[] args) throws ClassNotFoundException {
        Teacher teacher = new Teacher("张三", "123456");

        // 方式一:调用Class类的静态方法forName(String className)
        Class<?> c1 = Class.forName("com.loner.mj.reflection.Teacher");

        // 方式二:已知某个类的实例,调用该实例的getClass()方法,getClass是Object类中的方法。
        Class<? extends Teacher> c2 = teacher.getClass();

        // 方式三:已知具体类,通过类的class属性获取,该方法最安全可靠,程序性能最高
        Class<Teacher> c3 = Teacher.class;

        // 方式四:通过基本内置类型的包装类的TYPE属性获得CLass实例
        Class<Integer> c4 = Integer.TYPE;

        // 方式五:通过当前子类的Class对象获得父类的Class对象
        Class<?> c5 = c1.getSuperclass();
    }
}
ログイン後にコピー

#Class クラスの共通メソッド

## メソッド名

メソッド関数

##static Class forName(String name)##指定されたクラス名の Class オブジェクトを返しますパラメータなしのコンストラクターを呼び出し、Class オブジェクトのインスタンスを返しますReturn this Class オブジェクトによって表されるエンティティ (クラス、インターフェイス、配列クラス、または void) の名前次の Class オブジェクトを返します。現在の Class オブジェクトの親クラス 現在の Class オブジェクトのインターフェイスを返しますこのクラスのクラスローダーを返しますパラメータ リストに一致するメソッド名を取得します。 Methodすべての非継承メソッドを取得しますすべての非プライベート メソッドを取得##Field getDeclareField(String name)指定されたメソッドを取得属性#すべてのプロパティを取得#Field[] getFields()#Constructor getConstructor(Class...parameterTypes##パラメータ リストに一致するコンストラクター メソッドを取得しますクラスのすべてのコンストラクターを取得します#A getAnnotation(Class annotationClass)指定されたアノテーションを返すAnnotation[] getDeclaredAnnotations()すべてのアノテーションを返す
Obiect newInstance()
String getName()
Class getSuperclass()
Class[] getinterfaces()
ClassLoader getClassLoader()
Method getDeclareMethod(String name, Class ...parameterTypes)
Method[] getDeclareMethods()
Method[] getMethods()
##Field [] getDeclareFields()
すべての非プライベート プロパティを取得します
Constructor getConstructors()
##
public class ReflectionMethods {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
        Class<Worker> workerClass = Worker.class;

        /**
         * 类
         */
        System.out.println(workerClass.getName());
        System.out.println(workerClass.getSimpleName());
        System.out.println(workerClass.getSuperclass());
        System.out.println(workerClass.getPackage());
        Class<?>[] interfaces = workerClass.getInterfaces();
        for (Class<?> i : interfaces) {
            System.out.println(i);
        }

        /**
         * 属性
         */
        // 获取所有的属性
        Field[] declaredFields = workerClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        // 获取指定属性
        System.out.println(workerClass.getDeclaredField("username"));
        // 获取所有公共属性
        Field[] fields = workerClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        /**
         * 构造方法
         */
        // 获取所有构造方法
        Constructor<?>[] declaredConstructors = workerClass.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }
        // 获取指定的构造方法
        System.out.println(workerClass.getDeclaredConstructor(String.class, String.class));

        /**
         * 方法
         */
        // 获取所有的方法
        Method[] declaredMethods = workerClass.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        // 获取指定方法
        System.out.println(workerClass.getDeclaredMethod("getUsername", null));
        // 获取所有功能方法
        Method[] methods = workerClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
    }
}
ログイン後にコピー

哪些类型具有Class对象

public class InstantiationClass {
    public static void main(String[] args) throws ClassNotFoundException {
        // 类(外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。)
        Class<Object> objectClass = Object.class;
        // 接口
        Class<Comparable> comparableClass = Comparable.class;
        // 数组
        Class<String[]> stringClass = String[].class;
        Class<int[][]> intClass = int[][].class;
        // 枚举
        Class<ElementType> elementTypeClass = ElementType.class;
        // 注解
        Class<Override> overrideClass = Override.class;
        // 基本数据类型
        Class<Integer> integerClass = Integer.class;
        // void
        Class<Void> voidClass = void.class;
        // Class
        Class<Class> classClass = Class.class;
    }
}
ログイン後にコピー

2.3 反射的使用

反射操作对象

public class UseClass {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        Class<User> userClass = User.class;

        /**
         * 通过构造器实例化对象:不使用构造器,默认通过无参构造进行对象创建
         */
        Constructor<User> declaredConstructor = userClass.getDeclaredConstructor(String.class, String.class);
        User user = declaredConstructor.newInstance("张三", "123456");
        System.out.println(user);

        /**
         * 调用方法并执行相关操作
         */
        Method setUsername = userClass.getDeclaredMethod("setUsername", String.class);
        // invoke(Object, 参数):激活,即执行相关操作为该对象
        setUsername.invoke(user, "李四");
        Method setPassword = userClass.getDeclaredMethod("setPassword", String.class);
        setPassword.invoke(user, "123456");
        System.out.println(user);

        /**
         * 操作属性:通过反射直接操作私有属性会报错,需要通过setAccessible(ture)关闭访问安全检查,此方法属性、方法和构造都具有,会影响效率
         */
        Field username = userClass.getDeclaredField("username");
        username.setAccessible(true);
        username.set(user, "用户名");
        System.out.println(user);
    }
}
ログイン後にコピー

反射操作泛型

Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题。但是,一旦编译完成,所有和泛型有关的类型全部擦除。

为了通过反射操作这些类型,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型。

ParameterizedType:表示一种参数化类型,比如Collection

GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型

TypeVariable:是各种类型变量的公共父接口

WildcardType:代表一种通配符类型表达式

public class ClassOperateGenerics {
    public Map<String, String> list() {
        System.out.println("返回值是泛型");
        return new HashMap<>();
    }

    public void test(Map<String, User> map, List<Integer> list) {
        System.out.println("参数是泛型");
    }

    public static void main(String[] args) throws NoSuchMethodException {
        /**
         * 获取方法参数的泛型
         */
        Method method = ClassOperateGenerics.class.getMethod("test", Map.class, List.class);
        // 获取所有方法参数的泛型
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            // java.util.Map<java.lang.String, com.loner.mj.reflection.User>
            System.out.println(genericParameterType);
            if (genericParameterType instanceof ParameterizedType) {
                // 获取所有泛型的真实参数
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    // String, User, Integer
                    System.out.println(actualTypeArgument);
                }
            }
        }

        /**
         * 获取方法返回值的泛型
         */
        Method list = ClassOperateGenerics.class.getMethod("list", null);
        // 获取方法返回值的泛型
        Type genericReturnType = list.getGenericReturnType();
        if (genericReturnType instanceof ParameterizedType) {
            // 获取所有泛型的真实参数
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }
    }
}
ログイン後にコピー

反射操作注解

public class ClassOperateAnnotation {
    public static void main(String[] args) throws NoSuchFieldException {
        Class<People> peopleClass = People.class;

        // 获取类的所有注解
        Annotation[] declaredAnnotations = peopleClass.getDeclaredAnnotations();
        for (Annotation declaredAnnotation : declaredAnnotations) {
            System.out.println(declaredAnnotation);
        }
        // 获取类的注解的值
        Table declaredAnnotation = peopleClass.getDeclaredAnnotation(Table.class);
        System.out.println(declaredAnnotation.value());

        // 获取属性的注解
        Field name = peopleClass.getDeclaredField("name");
        Fields annotation = name.getAnnotation(Fields.class);
        System.out.println(annotation.name());
    }
}
ログイン後にコピー

以上がJava でアノテーションとリフレクションを使用する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:yisu.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート