反射、注解和反射的关系以及手写自己的注解。看完保证你能懂!

文章介绍了Java中通过反射创建对象和使用配置文件实现解耦合。同时,探讨了注解的工作原理,指出注解本身不执行操作,而是依赖于反射在运行时进行处理。通过自定义注解和反射,可以实现对类属性的赋值操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.一般我们会用反射来创建对象举个例子:先创建两个实体类Dog,Cat,然后再创建一个properties配置文件如下:

bean=com.ref.Dog

在后再通过反射来动态的创建这个两个实体类的对象:

public class MyTest {
    private static Properties properties;
    static {
        try {
            properties = new Properties();
            properties.load(MyTest.class.getClassLoader().getResourceAsStream("bean.properties"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) throws Exception {
        //获取properties的value(类的全限定名)
        String bean = properties.getProperty("bean");
        //通过反射拿到实体类
        Class clazz = Class.forName(bean);
        //创建它的无参构造器
        Constructor constructor = clazz.getConstructor(null);
        //创建实例对象
        Object object = constructor.newInstance(null);
        System.out.println(object);
    }
}

想要创建其他实体类对象的话可以直接在properties配置文件中修改bean的value即可,达到了解耦合的效果。

一般反射除了用在创建对象上,还用在注解上。我在已经创建的Dog实体类上添加的value注解:

@Data
@Component
public class Dog {

    @Value("1")
    private Integer id;

    @Value("旺财")
    private String name;
}

然后运行打印这个实体类的实例对象:Dog(id=1,name=旺财)。然后再打开这个value注解查看:

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
    String value();
}

发现什么逻辑都没有,那到底它是如何给我的实体类属性赋值的呢?注解到底是如何运行的?

注解不是单独运行,它是结合反射去运行的。意思是:注解只是一个标识,仅仅做一个标记作用,不做具体的操作,具体操作是由反射来完成的。

我们来写两个自己的注解来代替@value和@component:

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyValue {
    String value();
}
@Target({ElementType.TYPE})//指定是在那个目标上能用
@Retention(RetentionPolicy.RUNTIME)//配置运行的时候能生效
public @interface MyComponent {
}

并把这两个注解添加在我们的Dog实体类中:

@Data
@MyComponent
public class Dog {

    @MyValue("1")
    private Integer id;

    @MyValue("旺财")
    private String name;
}

但是此时它并不能给我们的实体类属性id,name赋值。需要通过反射机制来实现,反射启动之后,然后解析实体类Dog的信息,从而得到注解的指令,来完成赋值。具体操作如下:

public class Test {
    public static void main(String[] args) throws Exception{
        //获取Dog实体类
        Class<Dog> dogClass = Dog.class;
        //拿到Dog实体类中的MyComponent注解
        MyComponent myComponent = dogClass.getAnnotation(MyComponent.class);
        //判断Dog类中是否有MyComponent注解
        if (myComponent!=null){
            //创建对象
            Constructor<Dog> constructor = dogClass.getConstructor(null);
            Dog dog = constructor.newInstance(null);
            //开始赋值
            //获取全部的修饰符修饰的属性
            Field[] declaredFields = dogClass.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                //拿到属性上的MyValue注解
                MyValue valueAnnotation = declaredField.getAnnotation(MyValue.class);
                if (valueAnnotation!=null){
                    //获取注解上的value值
                    String value = valueAnnotation.value();
                    //暴力反射能给私有属性赋值
                    declaredField.setAccessible(true);
                    //判断属性的类型,如果属性是Integer则要把value转成Integer类型
                    if (declaredField.getType().getName().equals("java.lang.Integer")){
                        int val = Integer.parseInt(value);
                        declaredField.set(dog,val);
                    }else {
                        declaredField.set(dog,value);
                    }
                }
            }
            System.out.println(dog);
        } else {
            System.out.println("无法创建Dog对象");
        }
    }
}

最后执行main方法得到结果:

在这里插入图片描述

所以注解是依靠反射来实现的。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值