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方法得到结果:
所以注解是依靠反射来实现的。
标签:反射,实体类,Dog,value,注解,手写,ElementType,public From: https://blog.51cto.com/u_16376975/9125135