Java的反射(Reflection)、内省(Retrospector)和beanUtils工具

反射(Reflection)加载类,并解剖出类的各个组成部分(反射就是解剖的意思)
  • 加载类,获得类的字节码(三种方式):
  1. Class clazz1 = Class.forName("cn.xxx.bean.Person");
  2. Class clazz2 = new Person().getClass();
  3. Class clazz3 = Person().class;
  • 解剖出类中的各个组成部分:
获得公共构造方法、公共方法、和公共属性:
  1. public Constructor getConstructor(Class<?> ...ParameterTypes)
  2. public Method getMethod(String name, Class<?> ...parameterTypes)
  3. public Field getField(String name)  //或getFields获取所有属性
获得所有的构造方法、公共方法、和公共属性:
  1. public Constructor getDeclaredConstructor(Class<?>...ParameterTypes)
  2. public Method getDeclaredMethod(String name, Class<?>...parameterTypes)
  3. public Field getDeclaredField(String name)
反射一个类的构造方法,创建该类的对象:
  1. 反射无参数构造方法:Constructor c = clazz1.getConstructor(null); Person p = (Person) c.newInstance(null);
  2. 反射参数为String的构造方法:Constructor c = clazz1.getConstructor(String.class); Person p = (Person) c.newInstance("name");
  3. 反射参数为(String, int)的构造方法:Constructor c = clazz1.getConstructor(String.classint.class); Person p = (Person) c.newInstance("name", 123);
  4. 反射参数为List的私有构造方法:Constructor c = clazz1.getDeclaredConstructor(List.class); c.setAccessible(true); Person p = (Person) c.newInstance(new ArrayList());
  5. 简化的方式(无参数的情况):Person p = (Person) clazz1.newInstance();  //要求Person类中有无参的构造方法
反射并调用一个类的方法:
  1. 反射一个无参数的方法 aa1(){}:Method m = clazz1.getMethod("aa1", null); m.invoke(pnull); //p为前面创建的对象
  2. 反射带参数的方法 aa1(String, int){}:Method m = clazz1.getMethod("aa1", String.classint.class); m.invoke(p"张三", 38);
  3. 反射带参数的方法 aa1(String, int[]){}:Method m = clazz1.getMethod("aa1", String.class, int[].class); m.invoke(p"张三", new int[]{38, 39});
  4. 反射带参数的私有方法 aa1(InputString){}:Method m = clazz1.getDeclaredMethod("aa1", InputString.class); m.setAccessible(true)m.invoke(pnew FileInputStream("c:\\1.txt"));
  5. 反射带参数的静态方法 aa1(int){}:Method m = clazz1.getMethod("aa1", int.class); m.invoke(p, 23); //p可以用null代替
  6. 反射main(String[])方法:Method m = clazz1.getMethod("main", String[].class); m.invoke(null(Object)new String[]{"aa","bb"});  //注:一定要强转为一个Object,不然JDK为了向下兼容会把String[]先拆成两个参数再invoke,导致Wrong Number of Arguments错误
反射一个类中的属性:
  1. 获得一个属性的类型:Field f = clazz1.getField("name"); Class t = f.getType(); if(type.equals(String.class)){};
  2. 反射String name并获得它的值:Field f = clazz1.getField("name"); String name =(String) f.get(p); //p为前面创建的对象
  3. 反射String name并对它赋值:Field f = clazz1.getField("name"); String name =(String) f.set(p, "xxxxxx"); 
  4. 反射private int num:Field f = clazz1.getDeclaredField("num"); f.setAccessible(true); int num =(int) f.get(p); 
  5. 反射private static int age:Field f = clazz1.getDeclaredField("age"); f.setAccessible(true); int age=(int) f.get(p); 

内省(Introspector)用于方便地反射和操作Java Bean的属性
内省工具类:Introspector( java.beans.*包中
//获取Bean信息:
BeanInfo info = Introspector.getBeanInfo(Person.class); 
//注:如果不想获取所继承的属性,则用getBeanInfo(Person.class, stopClass.class); stopClass是某一个祖先类,这个例子表示只获得stopClass的子孙直到Person的属性,不包括stopClass。

  • 获得Bean的所有属性:
PropertyDescriptor[] pds = info.getPropertyDescriptors();

for (PropertyDescriptor pd : pds){
    System.out.println(pd.getName());    //获得属性的名称。注:只要有getter就算是一个属性,不一定要真正定义属性。实际上是获取getter中去掉“get”后把第一个字母变小写的字符串。
}

  • 获取Bean的一个属性:
PropertyDescriptor pd = new PropertyDescriptor("age", Person.class); //获得age属性
Method setter = pd.getWriteMethod();    //获得setter
setter.invoke(p, 45);    //p为之前获得的一个Person实例
Method getter = pd.getReadMethod();    //获得getter
System.out.println(getter.invoke(p, null)); 

获取一个属性的类型
 System.out.println(pd.getPropertyType());

  • 使用beanUtils(Apache开源项目)操纵java bean的属性:
需要使用第三方的包:commons-logging.jar, commons-beanutils-x.x.x.jar
//为属性name赋值:
BeanUtils.setProperty(p, "name", "Jack");   //p为一个Person实例

//自动类型转换:
BeanUtils.setProperty(p, "age", "123");   //如果age属性是int,BeanUtils会自动把字符串“123”转换为int类型
//注:BeanUtils缺省只支持把String转成8种基本数据类型。

//给BeanUtils注册类型转换器:
ConvertUtils.register(new Converter(){    //注册一个日期转换器:String转Date
        public Object convert(Class type, Object value){
            if(value==null){
                return null;
            }
            if(!(value instanceof String)){    //如果不是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);    //字符串转Date
            }catch(ParseException e){
                throw new RuntimeException(e); //e要传送给JVM
            }
        }
    }, Date.class);

BeanUtils.setProperty(p, "birthDate", "1980-01-02");    //  birthDate为Person中Date类型的属性

注:BeanUtils jar包中已经定义好了一些实现了Converter接口的转换器,比如:
ConvertUtils.register( new DateLocaleConverter(), Date. class);

//把map填充到bean中:
Map map = new HashMap();
map.put("name", "Jack");
map.put("birthdate", "1908-01-02");
...
ConvertUtils.register(new DateLocaleConverter(), Date.class);
Person p = new Persion();
BeanUtils.populate(p, map);    //map 填入 p 中


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值