1.为什么要学内省?
开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操作过于麻烦,所以sun公司开发了一套API,专门用于操作java对象的属性。
2.反射技术
以后我们能开发框架的时候,经常需要把一些数据封装到对象中去
需求:编写一个工厂方法根据配置文件的内容,工厂方法返回对应的对象,并且对象要有对应的属性值
Person.java
package day01.introspector;
public class Person {
int id;
String name;
public Person(int id, String name) {
super();
this.id = id;
this.name = name;
}
public Person() {
super();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + "]";
}
}
//obj.txt
day01.introspector.Person
id=110
name=张兵杰
//One.java
package day01.introspector;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class One {
Person p = (Person)getInstance();
System.out.println(p);
}
//根据配置文件生产对应的对象并且要把对象的属性值封装到对象中
public static Object getInstance() throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
BufferedReader bufferedReader = new BufferedReader(new FileReader("obj.txt"));
String className = bufferedReader.readLine();//读取配置文件获取到完整的类名
Class clazz = Class.forName(className);
//通过clazz对象获取到无参的构造方法
Constructor constructor = clazz.getConstructor(null);
//创建对象
Object o = constructor.newInstance(null);
//读取属性值
String line = null;
while((line = bufferedReader.readLine())!=null){
String[] datas = line.split("=");
//通过属性名获取到当前的Field对象
Field field = clazz.getDeclaredField(datas[0]);
if(field.getType() == int.class){
field.set(o, Integer.parseInt(datas[1]));
}else{
field.set(o, datas[1]);
}
}
return o;
}
}
//Two.java
package day01.introspector;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Two {
public static void main(String args[]) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException{
testProperty1();
}
public static void testProperty1() throws IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
Person p = new Person();
//属性描述器 属性名+属性类
PropertyDescriptor descriptor = new PropertyDescriptor("id",Person.class);
//获取属性对应的get或者是set方法设置或者获取属性
Method m = descriptor.getWriteMethod();//获取属性set方法
//执行该方法设置属性值
m.invoke(p, 110);
//Method类代表一个方法,invoke(调用)就是调用Method类代表的方法
Method readMethod = descriptor.getReadMethod();//获取属性get方法
System.out.println(p);
System.out.println(readMethod.invoke(p, null));
}
public void getAllProperty() throws IntrospectionException{
//Introspector 内省类
BeanInfo beanInfo = Introspector.getBeanInfo(Person.class);
//通过BeanInfo获取所有的属性描述器
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();//获取一个类中的所有属性描述器
for (PropertyDescriptor propertyDescriptor : descriptors) {
System.out.println(propertyDescriptor.getReadMethod());//get方法
}
}
}
BeanUtils:
BeanUtils主要解决的问题:把对象的属性数据封装到对象中BeanUtils的好处
1.BeanUtils设置属性值时候,如果属性是基本数据类型,BeanUtils会自动帮我们转化数据类型
2.BeanUtils设置属性值时候,底层也是依赖于get,set方法设置以及获取属性值的
3.BeanUtils设置属性值,如果设置的属性是其他的引用 类型数据,比如Date,那么这时候必须要注册一个类型转换器
//Three.java
package day01.introspector;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.text.SimpleDateFormat;
import javax.xml.crypto.Data;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
public class Three {
public static void main(String[] args) throws IllegalAccessException, InvocationTargetException {
//从文件中读取到的数据都是字符串的数据,或者是表单提交的数据获取到的时候也是字符串的数据
String id = "110";
String name = "张兵杰";
Person p = new Person();
BeanUtils.setProperty(p, "id", id);
BeanUtils.setProperty(p, "name", name);
System.out.println(p);
//日期不会自动转换,需要自己注册一个类型转换器
String birthday = "2017-7-25";
ConvertUtils.register(new Converter() {
@Override
public Object convert(Class type, Object value) {//type目前所遇到的数据类型。value目前参数的值
Date date = null;
try{
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
date = dateFormat.parse((String)value);
}catch(Exception e){
e.printStackTrace();
}
return date;
}
},Date.class);
}
}