JDK 之 Java Bean 內省機制
JDK 之 Java Bean 內省機制
JDK 規範目錄(https://www.cnblogs.com/binarylei/p/10200503.html)
JavaBean 是一種特殊的 Java 類,主要用於傳遞數據信息,這種 Java 類中的方法主要用於訪問私有的字段,且方法名符合某種命名規則。
一、JavaBean
1.1 JavaBean 命名規則
一個 JavaBean 類中的方法,去掉 set 或 get 前綴,剩余部分就是屬性名,如果剩余部分的第二個字母是小寫的,則把剩余部分的首字母改成小的。
getAge/setAge --> age
gettime --> time
setTime --> time如果去掉前綴,剩余部分的第二個字母為大寫,則全部大寫
getCPU --> getCPU
1.2 什麽叫做內省?
Java 內省主要使用來對 JavaBean 進行操作的,所以當一個類滿足了 JavaBean 的條件,就可以使用內省的方式來獲取和操作 JavaBean 中的字段值。內省提供了操作 JavaBean 的 API。
Java 中提供了一套 API 用來訪問某個屬性的 getter/setter 方法,通過這些 API 可以使你不需要了解這個規則,這些 API 存放於包 java.beans 中,一般的做法是通過類 Introspector 的 getBeanInfo 方法 來獲取某個對象的 BeanInfo 信息,然後通過 BeanInfo 來獲取屬性的描述器(PropertyDescriptor),通過這個屬性描述器就可以獲取某個屬性對應的 getter/setter 方法,然後我們就可以通過反射機制來調用這些方法。
二、JDK 內省機制
2.1 Introspector 類
Introspector 這個類位於 java.beans 包中,該類中的方法都是靜態的,可以直接使用類名調用。
// 獲取 beanClass 及其所有父類的 BeanInfo
BeanInfo getBeanInfo(Class<?>beanClass)
// 獲取 beanClass 及其指定到父類 stopClass 的 BeanInfo
BeanInfo getBeanInfo(Class<?> beanClass, Class<?> stopClass)
我們可以使用 Introspector 的 getBeanInfo(Class<?> beanClass) 來獲取一個 JavaBean 類的 BeanInfo 對象。BeanInfo 有三個常用的屬性:
// bean 信息 getBeanDescriptor
private BeanDescriptor beanDescriptor;
// 屬性信息 getPropertyDescriptors
private PropertyDescriptor[] properties;
// 方法信息 getMethodDescriptors
private MethodDescriptor[] methods;
實際工作中通過 BeanInfo 對象的 getPropertyDescriptors() 方法獲取屬性描述器 PropertyDescriptor 對象的數組,通過遍歷數組,可以獲取到每個字段相對應的屬性描述,通過描述器去獲取設置和獲取字段值的方法。
@Test
public void test() throws Exception {
BeanInfo beanInfo = Introspector.getBeanInfo(User.class, Object.class);
User user = new User();
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
String propertyName = propertyDescriptor.getName();
if (propertyName.equals("id")) {
propertyDescriptor.setPropertyEditorClass(IntPropertyEditor.class);
PropertyEditor propertyEditor = propertyDescriptor.createPropertyEditor(user);
propertyEditor.addPropertyChangeListener(evt -> {
PropertyEditor source = (PropertyEditor) evt.getSource();
Method writeMethod = propertyDescriptor.getWriteMethod();
try {
writeMethod.invoke(user, source.getValue());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
});
propertyEditor.setAsText("99");
}
}
System.out.println(user);
}
// JDK 中的 PropertyEditor 接口
public static class IntPropertyEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(Integer.parseInt(text));
}
}
2.2、PropertyDescriptor 類
這個類位於 java.beans 包中。
@Test
public void test() throws Exception {
PropertyDescriptor pd = new PropertyDescriptor("id", User.class);
System.out.println(pd.getName());
}
三、Apache BeanUtils 工具包
Apache 組織開發了一套用於操作 JavaBean 的 API(內省)。該工具在 commons-beanutils 包中,核心類 BeanUtils:
setProperty(bean, name, value)
copyProperties(target, source)
可以支持 String 到 8 中基本數據類型轉換,其他引用數據類型都需要註冊轉換器 ConvertUtils.register(Converter, Class)
使用 BeanUtils 來格式化日期:
public static void main(String[] args) throws Exception {
User user = new User();
String name = "zhangsan";
String birthday = "19801122";
// 註冊一個轉換器
/* 使用匿名內部類來註冊轉換器
ConvertUtils.register(new Converter() {
public Object convert(Class beanClass, Object value) {
String birthday = (String) value;
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
try {
return sdf.parse(birthday);
} catch (ParseException e) {
return null;
}
}
}, Date.class);
*/
DateConverter converter = new DateConverter();
converter.setPatterns(new String[]{"yyyy-MM-dd","yyyyMMdd","MM/dd/yyyy"});
ConvertUtils.register(converter, Date.class);
BeanUtils.setProperty(user, "name", name);
BeanUtils.setProperty(user, "birthday", birthday);
System.out.println(user);
}
參考:
- 《JavaBean 以及內省技術詳解》:https://www.cnblogs.com/yejiurui/archive/2012/10/06/2712693.html
每天用心記錄一點點。內容也許不重要,但習慣很重要!
JDK 之 Java Bean 內省機制