首先声明两个重要概念
1.反射
反射就是在运行状态把 Java 类中的各种成分映射成相应相应的 Java 类,可以动态得获取所有的属性以及动态调用任意一个方法。这里特被强调是任意类
2.内省
内省是通过反射的方式操作JavaBean的属性,jdk提供了PropertyDescription类来操作访问JavaBean的属性,Beantils工具基于此来实现。这里强调的是JavaBean(一种只有getter和setter方法的Java类,这是一种规范)而非任意类。因为PropertyDescription只有
getReadMethod() 来获得应该用于读取属性值的方法。
Method getWriteMethod() 来获得应该用于写入属性值的方法。
两个方法。
下面交代我们的正题的思路
我们的目的是用注解(一种可以理解为系统配置的技术)的方式来直接给属性(在这里是我们的一个自定义的对象)赋值。
我们分为以下的步骤(在此特别声明我们的这个对象在另一个类中充当Field,比如说一个person对象在另一个类中充当一个字段)
**1.用内省技术得到字段对象类型,并实例化(比如说得到了这个字段是属于Person类,然后实例化一个Person)
2.用反射技术得到注解中的信息
3.将注解中的信息整到这个字段上(在这里使用的也是内省技术)
4.测试这个字段的属性值来确认我们是否成功**
首先声明我们的JavaBean
package objectannotation;
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
接下来说明我们的注解类和注解信息
package objectannotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectPerson {
String name() default "hyl";
int age() default 15;
}
然后在声明我们的JavaBean在那个类中充当Field
package objectannotation;
public class PersonDao {
@InjectPerson(name="hyl",age=23)
Person person = new Person();
public Person getPerson(){
return person;
}
@InjectPerson(name="zhuliu",age=32)
public void setPerson(Person person){
this.person = person;
}
}
从这个类我们可以看出我们要注入的地方可以有两个
一个是
**@InjectPerson(name=”hyl”,age=23)
Person person = new Person();**
另一个是
@InjectPerson(name=”zhuliu”,age=32)
public void setPerson(Person person){
this.person = person;
}
接下来我们就来做两个测试将注解中的信息整到person字段上或者是person参数上,并且进行检验
测试1,将注解信息整到person字段上
package objectannotation;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test2 {
public static void main(String[] args) throws NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
//1.得到要注入的实例与写方法
//得到要注入的属性的描述(是那个类的那个方法或字段想注入)
Field f = PersonDao.class.getDeclaredField("person");//与getField不同他得到的是任意字段而非只有public
//得到要注入的对象的类型
Class clazz = f.getType();
//创建一个实例
Person person = (Person) clazz.newInstance();
//2.得到想要注入的对象的注解信息
//反射出属性上面的注解
InjectPerson inject = f.getAnnotation(InjectPerson.class);
Method[] methods = inject.getClass().getMethods();
//得到注解声明的信息来填充对象
for(Method m : methods){
String name = m.getName();
try {
PropertyDescriptor pd = new PropertyDescriptor(name,Person.class);//得到Person类中的名字为name的属性
Method set = pd.getWriteMethod();
//用指定对象指定参数去调用这个方法
set.invoke(person,m.invoke(inject, null));
} catch (Exception e) {
continue;
}
}
//3.用填充过后的对象来一些方法
PersonDao pdao = new PersonDao();
f.setAccessible(true);
f.set(pdao, person);
System.out.println(pdao.getPerson().getName());//zhuliu
}
}
2.测试1,将注解信息整到person参数上
package objectannotation;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws IntrospectionException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//得到要注入的属性描述在这里是person
PropertyDescriptor pd = new PropertyDescriptor("person",PersonDao.class);
//得到注入属性需要的类型
Class clazz = pd.getPropertyType();
//得到创建属性需要的对象
Object person = clazz.newInstance();
//得到属性的写方法
Method setPerson = pd.getWriteMethod();
//反射出方法上面的注解
InjectPerson inject = setPerson.getAnnotation(InjectPerson.class);
//得到注解声明的信息填充person
Method[] methods = inject.getClass().getMethods();
for(Method m : methods){
String name = m.getName();
try {
/*Field field = Person.class.getDeclaredField(name);
拿到对应的方法的注解的值
Object value = m.invoke(inject,null);
field.setAccessible(true);
field.set(person, value);*/
PropertyDescriptor pd1 = new PropertyDescriptor(name,Person.class);//得到Person类中的名字为name的属性
Method setmethod = pd1.getWriteMethod();
setmethod.invoke(person, m.invoke(inject, null));
} catch (Exception e) {
continue;
}
}
//把填充了信息的person整到PersonDao上面去
PersonDao pdao = new PersonDao();
//Person的set方法进行执行
setPerson.invoke(pdao,person);
System.out.println(pdao.getPerson().getName());//zhuliu
}
}
在以上的注释的代码块中是用反射的方法来操作JavaBean,由此可见操作JavaBean还是用内省比较简洁。
在此特别致敬方立勋老师!