Java注解和反射,你学会了吗?

2024年 1月 18日 54.3k 0

注解

注解(Annotation)是JDK5引入的一种代码辅助工具,其核心作用是对类、方法、变量、参数和包进行标注,通过反射来访问这些标注信息,以此在运行时改变所注解对象的行为,Java中的注解由内置注解和元注解组成。

注解与注释

  • Java注解又称之为Java标注,是JDK5开始支持加入源代码的特殊语法元数据
  • 普通的注释在编译后的class文件中是不存在的,而注解附加的信息则根据需要可以保存到class文件中,甚至运行期加载的class对象中

元注解介绍

创建注解

public @interface [AnnotationName]{}

元注解(描述注解的一种方式)

1.@Retention 定义注解的生命周期(source、class、runtime)2.@Documented 文档注解,会被javadoc工具文档化3.@Inherited 是否让子类继承该注解4.@Target 描述注解的应用范围,可选内容如下所示:

  • TYPE:可以用来修饰类、接口、注解类型或枚举类型
  • PACKAGE:可以用来修饰包
  • PARAMETER:可以用来修饰参数
  • ANNOTATION_TYPE:可以用来修饰注解类型
  • METHOD:可以用来修饰属性
  • FIELD:可以用来修饰属性(包括枚举常量)
  • CONSTRUCTOR:可以用来修饰构造器
  • LOCAL_VARIABLE:可以用来修饰局部变量

创建使用注解示例

注解的创建方式:

  • 配置元注解,由元注解来声明当前注解的作为范围和声明周期。
  • 注解中如果需要添加信息,可以用以上方式添加。
  • 注解信息支持java的基本数据结构。
  • 1.创建注解 @Study

    @Target({ElementType.FIELD, ElementType.TYPE}) // 元注解,定义注解的修饰范围,可以设置多个
    @Retention(RetentionPolicy.RUNTIME) // 元注解,定义注解的声明周期
    public @interface Study { // 注解内容可以设置值,也可以不设置值
    
        // 其中的属性是支持JAVA的八大属性的 byte、short、int、long、float、double、boolean、char
        // 如果属性为value,那么使用时,赋值可以不写 "value ="
    
        String name() default "Neco Deng"; // 表示定义了一个name属性,并且设置了默认值为Neco Deng
    
        String[] mores(); // 表示定义了一个名字为mores的字符串数组属性,并且没有默认值,即该属性需要显示定义
    }

    2.使用注解

    @Study(mores = {"first", "second"}) // 在类上使用注解,这里必须定义mores, 不然会报错
    public class Person {
    
        private int id;
    
        @Study(mores = {"first", "second"}) // 在属性上使用注解,这里必须定义mores, 不然会报错
        private String name;
    
    }

    反射

    反射(Reflection):在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射。

    反射的优缺点

    • 通过反射可以使程序代码访问装载到JVM中的类的内部信息,获取已装载类的属性信息,获取已装载类的方法,获取已装载类的构造方法信息。
    • 反射提供了JAVA程序的灵活性和扩展性,降低耦合性,提高自适应能力。
    • 反射会对性能造成一定的影响,同时让代码的可读性变低。

    常用的反射API

    方法名

    返回值

    参数描述

    Class.forName()

    获取类的元信息

    当前类文件的具体位置

    clazz.getClass()

    获取类的元信息

    clazz.getDeclaredFields()

    获取当前类中的所有属性

    当前类文件的具体位置

    setAccessible(true)

    设置当前属性为可见

    true或false

    getMethods()

    获取类所有方法

    invoke(obj)

    通过反射执行方法

    类的元信息

    getAnnotation(class)

    获取注解

    需要获取到额注解的Class

    例子

    public class ReflectionDemo {
    
    
        public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException,
                InstantiationException, NoSuchMethodException, InvocationTargetException {
            // 实例1:通过反射获取到Class元信息
            Person person = new Person();
            Class aClass2 = Class.forName("com.model.Person"); // 通过forName获取元信息
    
            // 实例2:通过反射获取类名,包名
            String name = aClass1.getName(); // 全路径类名 > cn.lazyfennec.model.Person
            String simpleName = aClass1.getSimpleName(); // 不包含路径 > Person
            Package aPackage = aClass1.getPackage(); // 包名 > package cn.lazyfennec.model
            System.out.println(name);
            System.out.println(simpleName);
            System.out.println(aPackage);
            System.out.println("===============================");
    
            // 实例3:获取类属性
            Field[] declaredFields = aClass1.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                System.out.println(declaredField);
            }
    
            // 实例4:获取类属性的具体的值
            person.setId(1);
            person.setName("Neco");
            for (Field declaredField : declaredFields) {
                declaredField.setAccessible(true); // 设置属性可见可访问,处理私有属性无法访问的问题
                System.out.println(declaredField.get(person));
            }
    
            // 实例4的另一种写法,只是简单的写法,可以进行优化
            Object obj = aClass1.newInstance(); // 实例化一个新的对象, 相当于反射中的实例化
            declaredFields = obj.getClass().getDeclaredFields();
            for (Field declaredField : declaredFields) {
                declaredField.setAccessible(true);
                if (declaredField.getName().equals("name")) {
                    declaredField.set(obj, "Neco");
                } else {
                    declaredField.set(obj, 1);
                }
                System.out.println(declaredField.get(obj));
            }
    
            // 实例5:反射获取当前类的方法
            Method[] methods = aClass1.getMethods();
            for (Method method : methods) {
                System.out.println(method.getName());
            }
            Method method = aClass1.getMethod("getString");
            Object invoke = method.invoke(obj);
            System.out.println(invoke);
    
            // 实例6:反射获得注解
            Study study = aClass1.getAnnotation(Study.class); // 从类中获取注解
            System.out.println(study);
            String[] mores = study.mores();
            String name1 = study.name();
            System.out.println("name: " + name1 + " mores: " + mores);
            // 从方法上获取注解
            methods = aClass1.getDeclaredMethods();
            for (Method method1 : methods) {
                Study annotation = method1.getAnnotation(Study.class);
                if (annotation == null) continue;
                String name2 = annotation.name();
                String[] mores1 = annotation.mores();
                System.out.println("name: " + name2 + " mores: " + mores1);
            }
            // 从属性上获取注解
            declaredFields = aClass1.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                Study annotation = declaredField.getAnnotation(Study.class);
                if (annotation == null) continue;
                String annotationName = annotation.name();
                String[] annotationMores = annotation.mores();
                System.out.println("name: " + annotationName + " mores: " + annotationMores);
            }
        }
    }

    参考

    https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/index.html

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论