反射比内省更容易理解一点。用一句比较白的话来概括,反射就是让你可以通过名称来得到对象 ( 类,属性,方法 ) 的技术,这种技术比内省机制使用范围更广泛。例如我们可以通过类名来生成一个类的实例;知道了方法名,就可以调用这个方法;知道了属性名就可以访问这个属性的值。
内省是 Java 语言对 Bean 类属性、事件的一种缺省处理方法。例如类 A 中有属性 name, 那我们可以通过 getName,setName 来得到其值或者设置新的值。通过 getName/setName 来访问 name 属性,这就是默认的规则。 Java 中提供了一套 API 用来访问某个属性的 getter/setter 方法,通过这些 API 可以使你不需要了解这个规则(但你最好还是要搞清楚),这些 API 存放于包 java.beans 中。
一般的做法是通过类 Introspector 来获取某个对象的 BeanInfo 信息,然后通过 BeanInfo 来获取属性的描述器( PropertyDescriptor ),通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后我们就可以通过反射机制来调用这些方法。
以下是BeanInfo的源代码,其中getMethodDescriptors,getPropertyDescriptors,getEventSetDescriptors分别用来取得素有的方法,变量,事件。
/*
* @(#)BeanInfo.java 1.28 03/12/19
*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package java.beans;
/**
* A bean implementor who wishes to provide explicit information about
* their bean may provide a BeanInfo class that implements this BeanInfo
* interface and provides explicit information about the methods,
* properties, events, etc, of their bean.
* <p>
* A bean implementor doesn't need to provide a complete set of
* explicit information. You can pick and choose which information
* you want to provide and the rest will be obtained by automatic
* analysis using low-level reflection of the bean classes' methods
* and applying standard design patterns.
* <p>
* You get the opportunity to provide lots and lots of different
* information as part of the various XyZDescriptor classes. But
* don't panic, you only really need to provide the minimal core
* information required by the various constructors.
* <P>
* See also the SimpleBeanInfo class which provides a convenient
* "noop" base class for BeanInfo classes, which you can override
* for those specific places where you want to return explicit info.
* <P>
* To learn about all the behaviour of a bean see the Introspector class.
*/
public interface BeanInfo {
/**
* Gets the beans <code>BeanDescriptor</code>.
*
* @return A BeanDescriptor providing overall information about
* the bean, such as its displayName, its customizer, etc. May
* return null if the information should be obtained by automatic
* analysis.
*/
BeanDescriptor getBeanDescriptor();
/**
* Gets the beans <code>EventSetDescriptor</code>s.
*
* @return An array of EventSetDescriptors describing the kinds of
* events fired by this bean. May return null if the information
* should be obtained by automatic analysis.
*/
EventSetDescriptor[] getEventSetDescriptors();
/**
* A bean may have a "default" event that is the event that will
* mostly commonly be used by humans when using the bean.
* @return Index of default event in the EventSetDescriptor array
* returned by getEventSetDescriptors.
* <P> Returns -1 if there is no default event.
*/
int getDefaultEventIndex();
/**
* Gets the beans <code>PropertyDescriptor</code>s.
*
* @return An array of PropertyDescriptors describing the editable
* properties supported by this bean. May return null if the
* information should be obtained by automatic analysis.
* <p>
* If a property is indexed, then its entry in the result array will
* belong to the IndexedPropertyDescriptor subclass of PropertyDescriptor.
* A client of getPropertyDescriptors can use "instanceof" to check
* if a given PropertyDescriptor is an IndexedPropertyDescriptor.
*/
PropertyDescriptor[] getPropertyDescriptors();
/**
* A bean may have a "default" property that is the property that will
* mostly commonly be initially chosen for update by human's who are
* customizing the bean.
* @return Index of default property in the PropertyDescriptor array
* returned by getPropertyDescriptors.
* <P> Returns -1 if there is no default property.
*/
int getDefaultPropertyIndex();
/**
* Gets the beans <code>MethodDescriptor</code>s.
*
* @return An array of MethodDescriptors describing the externally
* visible methods supported by this bean. May return null if
* the information should be obtained by automatic analysis.
*/
MethodDescriptor[] getMethodDescriptors();
/**
* This method allows a BeanInfo object to return an arbitrary collection
* of other BeanInfo objects that provide additional information on the
* current bean.
* <P>
* If there are conflicts or overlaps between the information provided
* by different BeanInfo objects, then the current BeanInfo takes precedence
* over the getAdditionalBeanInfo objects, and later elements in the array
* take precedence over earlier ones.
*
* @return an array of BeanInfo objects. May return null.
*/
BeanInfo[] getAdditionalBeanInfo();
/**
* This method returns an image object that can be used to
* represent the bean in toolboxes, toolbars, etc. Icon images
* will typically be GIFs, but may in future include other formats.
* <p>
* Beans aren't required to provide icons and may return null from
* this method.
* <p>
* There are four possible flavors of icons (16x16 color,
* 32x32 color, 16x16 mono, 32x32 mono). If a bean choses to only
* support a single icon we recommend supporting 16x16 color.
* <p>
* We recommend that icons have a "transparent" background
* so they can be rendered onto an existing background.
*
* @param iconKind The kind of icon requested. This should be
* one of the constant values ICON_COLOR_16x16, ICON_COLOR_32x32,
* ICON_MONO_16x16, or ICON_MONO_32x32.
* @return An image object representing the requested icon. May
* return null if no suitable icon is available.
*/
java.awt.Image getIcon(int iconKind);
/**
* Constant to indicate a 16 x 16 color icon.
*/
final static int ICON_COLOR_16x16 = 1;
/**
* Constant to indicate a 32 x 32 color icon.
*/
final static int ICON_COLOR_32x32 = 2;
/**
* Constant to indicate a 16 x 16 monochrome icon.
*/
final static int ICON_MONO_16x16 = 3;
/**
* Constant to indicate a 32 x 32 monochrome icon.
*/
final static int ICON_MONO_32x32 = 4;
}
一般来说,我们还可以使用Map和内省机制来构造一个Bean的实例对象,实例代码如下:
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.HashMap;
import java.util.Map;
import java.lang.reflect.InvocationTargetException;
public class MapToBean {
public static void main(String[] args) throws Exception {
Map<Object, Object> map = new HashMap<Object, Object>();
map.put("name", "张三");
map.put("age", 30);
Person p = convertMap(Person.class, map);
System.out.println(p.getName() + "," + p.getAge());
}
/**
*将一个Map对象转化为一个JavaBean
*
*@param type要转化的类型
*@param map 包含属性值的map
* @return转化出来的JavaBean对象
* @throwsIntrospectionException 如果分析类属性失败
*@throwsIllegalAccessException 如果实例化JavaBean失败
*@throwsInstantiationException 如果实例化JavaBean失败
*@throwsInvocationTargetException如果调用属性的setter方法失败
*/
private static<T> T convertMap(Class<T> type, Map<Object, Object> map) throws IntrospectionException,
IllegalAccessException,
InstantiationException,
InvocationTargetException {
BeanInfo beanInfo = Introspector.getBeanInfo(type);// 获取类属性
T t = type.newInstance();// 创建JavaBean对象
// 给JavaBean对象的属性赋值
for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {
String propertyName = descriptor.getName();
if (map.containsKey(propertyName)) {
// 下面一句可以try起来,这样当一个属性赋值失败的时候就不会影响其他属性赋值。
descriptor.getWriteMethod().invoke(t, map.get(propertyName));
}
}
return t;
}
}
class Person {
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;
}
}
参考地址:http://yangzhibin-java.iteye.com/blog/452068