(笔记十一)反射、JavaBean、内省、BeanUtils框架

来源:互联网 发布:开黑用什么软件 编辑:程序博客网 时间:2024/05/21 08:03
本节知识常常体验在框架中

1.反射

加载类,并解剖出类的各个组成部分(成员变量、方法、构造方法等)。框架中经常用到,如框架中通过设置配置文件,通过反射来加载对应的类。

a)加载类
Java中的Class类用于代表一个类的字节码,它提供加载类字节码的方法:Class.forName()
其他方法:
类名.class
对象.getClass() 

b)解剖类
getConstructor,getMethod,getFiled //public成员
getDeclaredConstructor... //所有成员
注:私有成员通过setAccessible(true)设置它为public

c)例子

package reflect;import java.util.List;public class Person {public String name = "aaa";public Person() {System.out.println("person");}public Person(String name) {System.out.println("person name");}private Person(List list){System.out.println("list");}public void Msg(){System.out.println("hello");}public void Msg(String msg){System.out.println(msg);}public void Msg(String[] msg){System.out.println(msg);}}
package reflect;import java.util.List;import java.lang.reflect.Constructor;import java.lang.reflect.Method;import java.util.ArrayList;import org.junit.Test;public class Demo {// 反射构造函数:public Person()@Testpublic void Test1() throws Exception {Class clazz = Class.forName("reflect.Person");Constructor c = clazz.getConstructor(null);Person p = (Person) c.newInstance(null);}// 反射构造函数:public Person(String name)@Testpublic void Test2() throws Exception {Class clazz = Class.forName("reflect.Person");Constructor c = clazz.getConstructor(String.class);Person p = (Person) c.newInstance("aaa");}// 反射构造函数:private Person(List list)@Testpublic void Test3() throws Exception {Class clazz = Class.forName("reflect.Person");Constructor c = clazz.getDeclaredConstructor(List.class);//获取私有c.setAccessible(true);//设置为可访问Person p = (Person) c.newInstance(new ArrayList());}////另一种方式,只能创建无参构造函数的对象@Testpublic void Test4() throws Exception {Class clazz = Class.forName("reflect.Person");Person p=(Person)clazz.newInstance();}//反射调用方法@Testpublic void Test5() throws Exception{Person p=new Person();Class clazz = Class.forName("reflect.Person");//无参Msg方法Method method=clazz.getMethod("Msg", null);method.invoke(p, null);//数组参数的Msg方法,1.5兼容1.4method=clazz.getMethod("Msg", String[].class);method.invoke(p, new Object[]{new String[]{"haha"}});}}

d)method.invoke在1.4与1.5中的差异

1.4中,method.invoke(Object o,Object obj[]),第一个参数为对象,第二个为参数列表,如
会将参数列表的数组,进行拆分,然后传递给方法的对应参数

1.5出现可变参数,method.nvoke(Object obj, Object... args),为了兼容1.4,继续拆分。
//反射数组参数的Msg方法
method=clazz.getMethod("Msg", String[].class);
method.invoke(p, new String[]{"aa","bb"}); //异常
原因:虽然1.5是可变参数,表面上直接去调用Msg(String[] arr),但兼容1.4,继续拆分
String[]可看作Object[],拆分后会查找Msg(String s1,String s2)的方法,该方法不存在,异常
解决:
method.invoke(p,(Object)new String[]{"aaa","bbb"});//方法1,Object仅仅是一个对象,拆成一个String[]
method.invoke(p,new Object[]{new String[]{"aaa","bbb"}});//方法2

e)字段
假设Person类,包含字段String name
Person p=new Person();
Field f=clazz.getField("name");
String name=(String)f.get(p); //1.直接获取某个对象的字段值
Class type=f.getType(); //2.安全获取字段值
Object value=f.get(p);
if(type.equals(String.class))
{
String n=(String)f.get(p);
}

2.JavaBean
本身是一种java类(封装数据),它的属性根据get或set来决定,格式:
a)必须有无参构造函数
b)字段必须私有
c)提供标准的getter或setter
public class Animal {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;}}
d)其实get或set开头的方法,称为类的属性

3.内省(Introspector)
利用反射,可以对JavaBean处理(换句话说,反射来处理类),但是过于麻烦,sun公司开发一套API,专门用于操作对象的属性。
内省提供了对JavaBean类属性、事件的一种缺省处理方法。通过getter、setter访问器,这是默认规则,通过内省API不需要了解规则来访问访问器
public class Person {private String Id;private String FirstName;public void setId(String id) {this.Id = id;}public String getId() {return this.Id;}public void setFirstName(String firstName) {this.FirstName = firstName;}public String getFirstName() {return this.FirstName;}}
public void Test() throws Exception{//获取Bean信息BeanInfo info=Introspector.getBeanInfo(Person.class);//获取Bean所有属性PropertyDescriptor[] pds=info.getPropertyDescriptors();for(PropertyDescriptor p : pds){System.out.println(p.getName());}//操作id属性Person person=new Person();PropertyDescriptor pd=new PropertyDescriptor("Id",Person.class);Method method=pd.getWriteMethod();method.invoke(person, "N001");System.out.println(person.getId());//得到属性类型System.out.println(pd.getPropertyType());}

4.BeanUtils框架,类似与内省,但提供更加方便的操作JavaBean
step1:在项目中新建lib文件夹,存放主要存放jar包,添加commons-logging.jar和commons-beanutils.jar.
step2:选中jar包,右键add Build Path,添加引用

Person.java文件

import java.util.Date;public class Person {private String name;private int age;private Date birthday;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;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}}

Demo1.java文件

import java.lang.reflect.InvocationTargetException;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;import org.apache.commons.beanutils.BeanUtils;import org.apache.commons.beanutils.ConversionException;import org.apache.commons.beanutils.ConvertUtils;import org.apache.commons.beanutils.Converter;import org.junit.Test;public class Demo1 {//基本用法@Testpublic void Test1() throws IllegalAccessException, InvocationTargetException{Person p=new Person();BeanUtils.setProperty(p, "name", "zhangsan");System.out.println(p.getName());}//注册日期转换器@Testpublic void Test2() throws IllegalAccessException, InvocationTargetException{String name="zhangsan";String age="20";String birthday="1989-01-01";//对beanUtils注册一个日期转换器ConvertUtils.register(new Converter(){public Object convert(Class type, Object value) {if(value==null){return null;}if(!(value instanceof String)){throw new ConversionException("只支持String类型转换");}String str=(String)value;if(str.trim().equals("")){return null;}SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");try{return df.parse(str);}catch(ParseException e){throw new RuntimeException(e);}}}, Date.class);Person p=new Person();BeanUtils.setProperty(p, "name", name);BeanUtils.setProperty(p, "age", age);//只支持8种基本数据转换BeanUtils.setProperty(p, "birthday", birthday);//使用日期转换器System.out.println(p.getName());System.out.println(p.getAge());System.out.println(p.getBirthday().toString());}}