• Java获取未知类型对象的属性


    获取未知类型对象的属性通常有两种方式:

    一是通过自定义注解的方式,通过获取被注解的属性从而获取属性的值,这种方式也是Spring参数注入的重要实现手段

    二是通过反射获取属性的名称,通过属性名从而获取属性,这种方式在开发时是比较简便易实现的。

    一、关于注解

    1、自定义注解

        首先定义一个@interface类型的注解接口

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ClassBeanId {
    
    }

         元注解的作用就是负责注解其他注解。
        1.@Target,
        2.@Retention,
        3.@Documented,
        4.@Inherited     这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们看一下每个元注解的作用和相应分参数的使用说明。


        @Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。
        作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
        取值(ElementType)有:
        1.CONSTRUCTOR:用于描述构造器
        2.FIELD:用于描述域
        3.LOCAL_VARIABLE:用于描述局部变量
        4.METHOD:用于描述方法
        5.PACKAGE:用于描述包
        6.PARAMETER:用于描述参数
        7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

        @Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。
        作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
        取值(RetentionPoicy)有:
        1.SOURCE:在源文件中有效(即源文件保留)
        2.CLASS:在class文件中有效(即class保留)
        3.RUNTIME:在运行时有效(即运行时保留)
    注:注解的的RetentionPolicy的属性值是RUTIME,这样注解处理器可以通过反射,获取到该注解的属性值,从而去做一些运行时的逻辑处理

    Annotation类型里面的参数该怎么设定:
        第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型; 
        第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;
        第三,如果只有一个参数成员,最好把参数名称设为"value",后加小括号。

    例如:

    示例1:

    自定义一个注解:

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ClassBeanId {
        public int id() default -1;
    
    }

    使用这个注解:

    public class ClassBean {
        @ClassBeanId(id = 20) //使用已定义的注解默认值为20。如果需要赋值,就需要用反射将id的值取出来并赋给当前类的id
        private int id;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        @Override
        public String toString() {
            return "ClassBean [id=" + id + "]";
        }
        
    }

    定义获取该注解下的属性

    public static <T> void getData(T data) throws IllegalArgumentException, IllegalAccessException{
            int id = 0;
            Class clazz = data.getClass();
            Field[] fields = clazz.getDeclaredFields();
            for(Field field : fields){
                if(field.getAnnotation(ClassBeanId.class) != null){
                    field.setAccessible(true);
                    id = field.getInt(data);
                }
                System.out.println("id : "+id);
            }
        }

    将对象传入该方法中,通过反射判断该对象属性是否添加了注解,从而获取该对象的id属性。

    若要实现类似Spring框架中的参数注入,则需要重新定义一组方法,将注解中的参数传入对象之中,方法如下:

    public static <T> void getDataFromAnnotation(T data) throws IllegalArgumentException, IllegalAccessException{
            int id = 0;
            Class clazz = data.getClass();
            Field[] fields = clazz.getDeclaredFields();
            for(Field field : fields){
                if(field.getAnnotation(ClassBeanId.class) != null){  //判断该属性是否被注解
                    field.setAccessible(true);
                    ClassBeanId classBeanId = field.getAnnotation(ClassBeanId.class); //实例该注解
                    field.setInt(data, classBeanId.id());  //获取注解的值并赋值给传入对象
                }
            }
        }

    虽然并非严格的Spring框架的实现机制,但是原理是相同的。

    二、关于反射

    通过反射获取属性的名称,并对比属性命名就可以获取未知类型对象中某些属性值。这是一种比较常见的做法。

    public static <T> void getDataField(T data) throws IllegalArgumentException, IllegalAccessException{
            Class clazz = data.getClass();
            Field[] fields = clazz.getDeclaredFields();
            for(Field field : fields){
                String name = field.getName();
                if(name.equals("id")){
                    field.setAccessible(true);
                    field.setInt(data,29);
                }
            }
        }
  • 相关阅读:
    指针与引用
    const常量
    函数初始化列表
    Ubuntu18.04.3主力开发机使用记录(一)
    ZUI(BootStrap)使用vue动态插入HTMl所创建的data-toggle事件初始化方法
    一次JDBC支持表情存储的配置过程
    Springboot Rabbitmq 使用Jackson2JsonMessageConverter 消息传递后转对象
    搭建谷歌浏览器无头模式抓取页面服务,laravel->php->python->docker !!!
    Laravel 命令行工具之多线程同步大批量数据 DB连接混乱 解决方案
    nginx 之负载均衡 :PHP session 跨多台服务器配置
  • 原文地址:https://www.cnblogs.com/yuanblog/p/4442995.html
Copyright © 2020-2023  润新知