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

时间: 2024-08-05 22:28:18

Java核心_内省的相关文章

Java核心 --- 枚举

Java核心 --- 枚举 枚举把显示的变量与逻辑的数字绑定在一起在编译的时候,就会发现数据不合法也起到了使程序更加易读,规范代码的作用 一.用普通类的方式实现枚举 新建一个终态类Season,把构造方法设为私有,因为枚举值不能随意增加因为不能new出这个类的对象,所以需要定义成员变量,把new写在类的内部这样,就可以在类的外部通过访问类的静态成员变量的方式访问到枚举值通过这样的方式,只能在类的外部使用在枚举类的内部定义的枚举值 类Season里面是可以有方法的,我们设置地球又公转了四分之一方法

Java核心编程快速学习

Java核心编程部分的基础学习内容就不一一介绍了,本文的重点是JAVA中相对复杂的一些概念,主体内容如下图所示. 反射reflect是理解Java语言工作原理的基础,Java编译器首先需要将我们编写的.java源文件编译为.class字节码,然后再JVM虚拟机上运行,接下来通过一个表格,来了解反射的基本操作. 功能 示例 泛化的Class引用 Class<?> intClass = int.class Class<? extends Number> bounded = int.cl

Java泛型_上界extends_下界super

?Java泛型_上界extends_下界super ? 通配符类型 <? extends T> 表示类型的上界,表示参数化类型的可能是T或是T的子类 <? super T> 表示类型下界(Java Core中叫超类型限定),表示参数化类型是此类型(T)的超类型(父类型),直至Object 当使用 Upper Bound 通配符时 如下代码, /**  * 代码中通配符<?> 是 <? extends Object> 的简写  *  * @param list

Java核心知识点学习----多线程中的阻塞队列,ArrayBlockingQueue介绍

1.什么是阻塞队列? 所谓队列,遵循的是先进先出原则(FIFO),阻塞队列,即是数据共享时,A在写数据时,B想读同一数据,那么就将发生阻塞了. 看一下线程的四种状态,首先是新创建一个线程,然后,通过start方法启动线程--->线程变为可运行可执行状态,然后通过数据产生共享,线程产生互斥---->线程状态变为阻塞状态---->阻塞状态想打开的话可以调用notify方法. 这里Java5中提供了封装好的类,可以直接调用然后构造阻塞状态,以保证数据的原子性. 2.如何实现? 主要是实现Blo

Java核心知识点学习----多线程 倒计时记数器CountDownLatch和数据交换的Exchanger

本文将要介绍的内容都是Java5中的新特性,一个是倒计时记数器---CountDownLatch,另一个是用于线程间数据交换的Exchanger. 一.CountDownLatch 1.什么是CountDownLatch? 倒计时计数器,调用CountDownLatch对象的CountDown()方法就将计数器减一,当计数到达0时,则所有等待者或者全部等待者开始执行. 2.如何用? new CountDownLatch(1); 直接new,其构造函数必须传一个int类型的参数,参数的意思是: c

Java核心:类加载和JVM内存的分配

类的加载: 指的是将class文件的二进制数据读入到运行时数据区(JVM在内存中划分的) 中,并在方法区内创建一个class对象. 类加载器: 负责加载编译后的class文件(字节码文件)到JVM(Java虚拟机)当中. 而类加载器主要分为以下几种: 1.Bootstrap class loader (引导类加载器) 负责加载Java核心类库.在jre\lib目录下,包括rt.jar(Java基础类库),这些 都是Java的核心类库.而且这个加载器是由C语言编写的,所以在Java程序中是获取 不

深入Java核心 Java内存分配原理精讲

栈.堆.常量池虽同属Java内存分配时操作的区域,但其适用范围和功用却大不相同.本文将深入Java核心,详细讲解Java内存分配方面的知识. Java内存分配与管理是Java的核心技术之一,之前我们曾介绍过Java的内存管理与内存泄露以及Java垃圾回收方面的知识,今天我们再次深入Java核心,详细介绍一下Java在内存分配方面的知识.一般Java在内存分配时会涉及到以下区域: ◆寄存器:我们在程序中无法控制 ◆栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中 ◆堆:存

通过jstack定位在线运行java系统故障_案例1

问题描述: 在一个在线运行的java web系统中,会定时运行一个FTP上传的任务,结果有一天发现,文件正常生成后却没有上传. 问题初步分析: 1.查看日志文件 发现这个任务只打印了开始进入FTP处理的日志,但是没有打印FTP处理完成的日志. 从代码上看,FTP上传处理的代码异常保护都非常的好,如果出现异常,就会进行打印,而日志文件中却没有相关的信息,甚是奇怪.怀疑是FTP过程问题,如对方FTP服务器有什么问题导致,但是却找不到证据. 苦于无法窥探java运行系统内部信息,祭出杀手锏-jstac

Java核心 --- 泛型

CoreJava 泛型 java泛型的出现避免了强制类型转换,便于代码更好的被阅读 本文的写作参照了张孝祥的泛型介绍:http://www.itcast.cn/news/dbfd20f1/f4b1/412d/9b40/c1a81b8bf1da.shtml 更多疑问请参考:http://www.vaikan.com/java-generics-quick-tutorial/ 1.可以接收类型参数的类型在接受类型参数后变为泛型,但是,虽然是不同的泛型但是还是相同的类型 package com.yuk