Java核心_内省
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
Java核心_内省的更多相关文章
- Java核心 --- 枚举
Java核心 --- 枚举 枚举把显示的变量与逻辑的数字绑定在一起在编译的时候,就会发现数据不合法也起到了使程序更加易读,规范代码的作用 一.用普通类的方式实现枚举 新建一个终态类Season,把构造 ...
- 深入Java核心 Java中多态的实现机制(1)
在疯狂java中,多态是这样解释的: 多态:相同类型的变量,调用同一个方法时,呈现出多中不同的行为特征, 这就是多态. 加上下面的解释:(多态四小类:强制的,重载的,参数的和包含的) 同时, 还用人这 ...
- Java核心:类加载和JVM内存的分配
类的加载: 指的是将class文件的二进制数据读入到运行时数据区(JVM在内存中划分的) 中,并在方法区内创建一个class对象. 类加载器: 负责加载编译后的class文件(字节码文件)到JVM(J ...
- 深入Java核心 Java内存分配原理精讲
深入Java核心 Java内存分配原理精讲 栈.堆.常量池虽同属Java内存分配时操作的区域,但其适用范围和功用却大不相同.本文将深入Java核心,详细讲解Java内存分配方面的知识. Java内存分 ...
- java开发_模仿百度文库_OpenOffice2PDF_注意事项
在模仿百度文库的操作过程中,有很多朋友反映出来的一些问题,是我想起了写这篇blog. 主要是让大家在做的过程中注意一些东西,否则达不到想要的效果. 第一步:我们先从 java开发_模仿百度文库_Ope ...
- Java核心知识点学习----多线程中的阻塞队列,ArrayBlockingQueue介绍
1.什么是阻塞队列? 所谓队列,遵循的是先进先出原则(FIFO),阻塞队列,即是数据共享时,A在写数据时,B想读同一数据,那么就将发生阻塞了. 看一下线程的四种状态,首先是新创建一个线程,然后,通过s ...
- Java核心知识点学习----使用Condition控制线程通信
一.需求 实现线程间的通信,主线程循环3次后,子线程2循环2次,子线程3循环3次,然后主线程接着循环3次,如此循环3次. 即:A->B->C---A->B->C---A-> ...
- Java核心知识点学习----线程中如何创建锁和使用锁 Lock,设计一个缓存系统
理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...
- Java核心 --- 注解
Java核心——注解 注解是jdk5以后的新特性,Spring和Hibernate等框架提供了注解的配置方式使用, 本文参考了浪曦风中叶的注解讲解,主要讲解jdk内置注解的用法,注解的声明和定义,以及 ...
随机推荐
- 271. Encode and Decode Strings
题目: Design an algorithm to encode a list of strings to a string. The encoded string is then sent ove ...
- Android setStartOffset方法:设置启动时间
[功能说明]该方法用于设置一个动画执行的启动时间,单位为毫秒.系统默认当执行start方法后立刻执行动画,当使用该方法设置后,将延迟一定的时间再启动动画. [基本语法]public void setS ...
- 机器人学 —— 轨迹规划(Sampling Method)
上一篇提到,机器人轨迹规划中我们可以在 Configuration Space 中运行A* 或者 DJ 算法.无论A* 还是DJ 算法,都必须针对邻域进行搜索,如果2自由度则有4邻域,2自由度则有8邻 ...
- PowerDesigner中name和code取消自动关联
PowerDesigner中,如果修改了某个字段的name,其code也跟着修改,如果想取消,可以如下操作 解决方法如下: 1.选择Tools->GeneralOptions...菜单,出现Ge ...
- java 无法找到main类解决办法
java 无法找到main类解决办法 如果Java类有包名,你必须建相应的包文件夹并把文件编译或拷贝到到相应的文件夹下: 如下: 1.源文件文件: E:\test\src\tes ...
- centos 升级GCC/G++
#get rep yum install centos-release-scl-rh #yum install centos-release-scl # install g++ 5.2.1 yum - ...
- ACdream 1735 输油管道 (排序)
http://acdream.info/problem?pid=1735 官方题解:http://acdream.info/topic?tid=4246 因为主干线是平行于x轴的直线,那么跟x坐标其实 ...
- php注册登录系统(一)-极简
序 登录注册系统是日常上网最普通的操作,我设了一个分类一步步完善注册登录系统,若有哪里错误请慧教 所用语言:php 数据库 :mysql 本次实现功能: 1.用户注册 2.用户登录 主要文件: 完整代 ...
- JAVA网络编程【转】出处不详
网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编 ...
- IntelliJ IDEA创建第一个Java小程序
我尝试了汉化,会影响IDE部分功能. 其实IDE完全没必要汉化,就那么几个单词,不懂的话,就有道字典查一下吧. 汉化易于入门,不汉化一样可以使用. 我爱这个编辑器,非常之强大,就是比较占内存. 我爱这 ...