Java核心_内省
查看java的api,发现有一个包java.bean
咦,这个包是干什么的呢,原来,它是用来操作JavaBean对象的!
一、内省操作
①JavaBean:一种特殊的Java类
无参构造方法,每个属性提供getter和setter
/Introspector/src/yuki/core/introspector/bean/Point.java
package yuki.core.introspector.bean; public class Point { private int x; private int y; public Point(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } }
获取设置值
用内省获取属性值与设置属性值
/Introspector/src/yuki/core/introspector/test/PointTest1
package yuki.core.introspector.test; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import yuki.core.introspector.bean.Point; public class PointTest { /** * 获得point对象的getX方法的值 * 如果用反射,需要得到x的字段名 * 然后首字母大写,前面加get,拼成getX * 然后调用这个对象的方法拿到x属性 * 这里不演示 * * 如果用内省的方法,可以...... * @throws Exception */ public static void main(String[] args) throws Exception { Point p = new Point(3, 4); String propertyName = "x"; // x --> X --> getX --> MethodGetX PropertyDescriptor pd = new PropertyDescriptor(propertyName, p.getClass()); Method methodGetX = pd.getReadMethod(); Object retVal = methodGetX.invoke(p); System.out.println(retVal); Method methodSetX = pd.getWriteMethod(); methodSetX.invoke(p, 7); System.out.println(p.getX()); } }
运行结果如下:
3 7
②抽取方法
使用Eclipse从代码中抽取出方法
Refractor>Extract Method...>MethodName=
/Introspector/src/yuki/core/introspector/test/PointTest2
package yuki.core.introspector.test; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import yuki.core.introspector.bean.Point; public class PointTest { public static void main(String[] args) throws Exception { Point p = new Point(3, 4); String propertyName = "x"; Object retVal = getProperty(p, propertyName); System.out.println(retVal); Object value = 7; setProperty(p, propertyName, value); System.out.println(p.getX()); } private static void setProperty(Object p, String propertyName, Object value) throws IntrospectionException, IllegalAccessException, InvocationTargetException { PropertyDescriptor pd2 = new PropertyDescriptor(propertyName, p.getClass()); Method methodSetX = pd2.getWriteMethod(); methodSetX.invoke(p, value); } private static Object getProperty(Object p, String propertyName) throws IntrospectionException, IllegalAccessException, InvocationTargetException { PropertyDescriptor pd = new PropertyDescriptor(propertyName, p.getClass()); Method methodGetX = pd.getReadMethod(); Object retVal = methodGetX.invoke(p); return retVal; } }
运行结果如下:
3 7
③BeanInfo对象
调用IntroSpector.getBeanInfo可以得到BeanInfo对象,
BeanInfo对象封装了把这个类当作JavaBean看的结果信息
/Introspector/src/yuki/core/introspector/test/PointTest3
package yuki.core.introspector.test; 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; import yuki.core.introspector.bean.Point; public class PointTest { public static void main(String[] args) throws Exception { Point p = new Point(3, 4); String propertyName = "x"; Object retVal = getProperty(p, propertyName); System.out.println(retVal); } private static Object getProperty(Object p, String propertyName) throws IntrospectionException, IllegalAccessException, InvocationTargetException { BeanInfo beanInfo = Introspector.getBeanInfo(p.getClass()); PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); Object retVal = null; for(PropertyDescriptor pd : pds){ if(pd.getName().equals(propertyName)){ Method methodGetX = pd.getReadMethod(); retVal = methodGetX.invoke(p); break; } } return retVal; } }
运行结果如下:
3
二、BeanUtils工具包操作JavaBean
①Apache提供的工具包
http://commons.apache.org/proper/commons-beanutils/download_beanutils.cgi
commons-beanutils-1.9.2-bin.zip/commons-beanutils-1.9.2.jar
报错:java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
还需要提供日志包:commons-logging-1.1.3.jar
再次运行得到x的值为3,设置x的值为9
/Introspector/src/yuki/core/introspector/test/PointTest.java
package yuki.core.introspector.test; import org.apache.commons.beanutils.BeanUtils; import yuki.core.introspector.bean.Point; public class PointTest { public static void main(String[] args) throws Exception { Point p = new Point(3, 4); String x = BeanUtils.getProperty(p, "x"); System.out.println(x); BeanUtils.setProperty(p, "x", 9); System.out.println(p.getX()); System.out.println(BeanUtils.getProperty(p, "x").getClass().getName()); } }
运行结果如下:
3 9 java.lang.String
字符串类型与属性类型的自动转换
但是,得到x的结果类型为字符串,但是实际值为int
因为从浏览器中获取的值是字符串,如果设置的是"9"的字符串,就会自动转换成int
而显示在网页上的值也是是字符串,所以,这样的设定提供了很大的便捷
②属性的级联操作
假设有一个属性是日期类型
类Date有一个方法,setTime(long time); 所以可以认为Date有一个time的属性
属性birth是一个复合属性,所以可以Date的毫秒值
直接获取cat.getBirth()得到的是null,这是因为没有给birth对象赋初值;
/Introspector/src/yuki/core/introspector/bean/Cat.java
package yuki.core.introspector.bean; import java.util.Date; public class Cat { private Date birth; private String name; private Integer age; public Cat() {} public Cat(Date birth) { this.birth = birth; } public Cat(Date birth, String name, Integer age) { this.birth = birth; this.name = name; this.age = age; } public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Cat [birth=" + birth + ", name=" + name + ", age=" + age + "]"; } }
/Introspector/src/yuki/core/introspector/test/CatTest.java
package yuki.core.introspector.test; import java.util.Date; import org.apache.commons.beanutils.BeanUtils; import yuki.core.introspector.bean.Cat; public class CatTest { public static void main(String[] args) throws Exception { Cat cat = new Cat(); cat.setBirth(new Date()); BeanUtils.setProperty(cat, "birth.time", "10001000"); System.out.println(cat.getBirth()); String birth_time = BeanUtils.getProperty(cat, "birth.time"); System.out.println(birth_time); } }
运行结果如下:
Thu Jan 01 10:46:41 CST 1970 10001000
③BeanUtils的函数
一个对象上的属性拷贝到另外一个对象
public static void copyProperties(Object dest, Object orig)
一个JavaBean的属性转换成Map
public static Map<String,String> describe(Object bean)
Map转换成一个JavaBean的属性
public static void populate(Object bean, Map<String,? extends Object> properties)
/Introspector/src/yuki/core/introspector/map/BeanUtilsTest.java
package yuki.core.introspector.map; import java.util.Date; import java.util.HashMap; import java.util.Map; import org.apache.commons.beanutils.BeanUtils; import yuki.core.introspector.bean.Cat; public class BeanUtilsTest { public static void main(String[] args) throws Exception { //Map --> JavaBean Cat cat = new Cat(); Map<String, Object> map = new HashMap<String, Object>(); map.put("name", "Tom"); map.put("age", 12); BeanUtils.populate(cat, map); System.out.println(cat); //JavaBean --> Map Map<String, String> map2 = BeanUtils.describe(cat); for(Map.Entry<String, String> entry : map2.entrySet()){ System.out.println(entry.getKey() + " -> " + entry.getValue()); } //cat --> cat2 Cat cat2 = new Cat(new Date(), null, 14); BeanUtils.copyProperties(cat2, cat); System.out.println(cat2); } }
运行结果如下:
Cat [birth=null, name=Tom, age=12] name -> Tom birth -> null class -> class yuki.core.introspector.bean.Cat age -> 12 Cat [birth=null, name=Tom, age=12]
④PropertyUtils的函数
这个对象的函数setProperty和getProperty的类型转换是没有字符串的
/Introspector/src/yuki/core/introspector/map/PropertyUtilsTest.java
package yuki.core.introspector.map; import org.apache.commons.beanutils.PropertyUtils; import yuki.core.introspector.bean.Cat; public class PropertyUtilsTest { public static void main(String[] args) throws Exception { Cat cat = new Cat(); PropertyUtils.setProperty(cat, "age", 11); System.out.println(cat); System.out.println(PropertyUtils.getProperty(cat, "age").getClass().getName()); } }
运行结果如下:
Cat [birth=null, name=null, age=11] java.lang.Integer
以上的内容参考了[张孝祥Java高新技术_内省]
三、用同一个类的对象更新这个对象的属性
一般用作表单中取得的对象更新数据库中的对象
①反射的方式
spring的 @Autowire标签可以不用写setter方法就可以实现自动编织
/Introspector/src/yuki/core/introspector/field/FieldUtil.java
package yuki.core.introspector.field; import java.lang.reflect.Field; import java.util.Date; import yuki.core.introspector.bean.Cat; public class FieldUtil { public static void main(String[] args) throws Exception { Cat c1 = new Cat(new Date(12345), "Tom", 11); Cat c2 = new Cat(); FieldUtil.updateField(c1, c2); System.out.println(c1); c1 = new Cat(new Date(12345), "Tom", 11); c2 = new Cat(new Date(), "", null); FieldUtil.updateField(c1, c2); System.out.println(c1); c1 = new Cat(new Date(12345), "Tom", 11); c2 = new Cat(new Date(), "Gaffey", null); FieldUtil.updateField(c1, c2); System.out.println(c1); c1 = new Cat(new Date(12345), "Tom", 11); c2 = new Cat(null, "Gaffey", 13); FieldUtil.updateField(c1, c2); System.out.println(c1); } /** * 用同一个类的对象更新这个对象的属性 * @param dest 目标对象,一般属数据库中取出的的对象 * @param orig 赋值对象,一般是表单中取得的对象 * @throws IllegalAccessException * @throws IllegalArgumentException */ public static <T> void updateField(T dest, T orig) throws IllegalArgumentException, IllegalAccessException { Field[] fs = dest.getClass().getDeclaredFields(); for(Field f : fs){ try { f.setAccessible(true); Object val = f.get(orig); if(val != null && !"".equals(val)){ f.set(dest, val); } } finally { f.setAccessible(false); } } } }
运行结果如下:
Cat [birth=Thu Jan 01 08:00:12 CST 1970, name=Tom, age=11] Cat [birth=Sat Oct 18 01:56:21 CST 2014, name=Tom, age=11] Cat [birth=Sat Oct 18 01:56:21 CST 2014, name=Gaffey, age=11] Cat [birth=Thu Jan 01 08:00:12 CST 1970, name=Gaffey, age=13]
②内省的方式
/Introspector/src/yuki/core/introspector/field/PropertyUtil.java
package yuki.core.introspector.field; 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; import java.util.Date; import yuki.core.introspector.bean.Cat; public class PropertyUtil { public static void main(String[] args) throws Exception { Cat c1 = new Cat(new Date(12345), "Tom", 11); Cat c2 = new Cat(); PropertyUtil.updateProperty(c1, c2); System.out.println(c1); c1 = new Cat(new Date(12345), "Tom", 11); c2 = new Cat(new Date(), "", null); PropertyUtil.updateProperty(c1, c2); System.out.println(c1); c1 = new Cat(new Date(12345), "Tom", 11); c2 = new Cat(new Date(), "Gaffey", null); PropertyUtil.updateProperty(c1, c2); System.out.println(c1); c1 = new Cat(new Date(12345), "Tom", 11); c2 = new Cat(null, "Gaffey", 13); PropertyUtil.updateProperty(c1, c2); System.out.println(c1); } /** * 用同一个类的对象更新这个对象的属性 * @param dest 目标对象,一般属数据库中取出的的对象 * @param orig 赋值对象,一般是表单中取得的对象 * @throws IntrospectionException * @throws InvocationTargetException * @throws IllegalArgumentException * @throws IllegalAccessException */ public static <T> void updateProperty(T dest, T orig) throws IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { BeanInfo beanInfo = Introspector.getBeanInfo(dest.getClass()); PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); for(PropertyDescriptor pd : pds){ Method read = pd.getReadMethod(); Object val = read.invoke(orig); if(val != null && !"".equals(val)){ Method write = pd.getWriteMethod(); if(write != null) write.invoke(dest, val); } } } }
运行结果如下:
Cat [birth=Thu Jan 01 08:00:12 CST 1970, name=Tom, age=11] Cat [birth=Sat Oct 18 01:57:35 CST 2014, name=Tom, age=11] Cat [birth=Sat Oct 18 01:57:35 CST 2014, name=Gaffey, age=11] Cat [birth=Thu Jan 01 08:00:12 CST 1970, name=Gaffey, age=13]
本文的目录结构:
更多好文请关注:http://www.cnblogs.com/kodoyang/
请点击下方红色的" 关注我 ",关注我吧!
kongdongyang
2014/10/18