1. 程式人生 > >JDK 之 Java Bean 內省機制

JDK 之 Java Bean 內省機制

遍歷 methods prop oca try info 靜態 illegal int

JDK 之 Java Bean 內省機制

JDK 規範目錄(https://www.cnblogs.com/binarylei/p/10200503.html)

JavaBean 是一種特殊的 Java 類,主要用於傳遞數據信息,這種 Java 類中的方法主要用於訪問私有的字段,且方法名符合某種命名規則。

一、JavaBean

1.1 JavaBean 命名規則

  1. 一個 JavaBean 類中的方法,去掉 set 或 get 前綴,剩余部分就是屬性名,如果剩余部分的第二個字母是小寫的,則把剩余部分的首字母改成小的。

    getAge/setAge --> age
    gettime --> time
    setTime --> time

  2. 如果去掉前綴,剩余部分的第二個字母為大寫,則全部大寫

    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);  
}

參考:

  1. 《JavaBean 以及內省技術詳解》:https://www.cnblogs.com/yejiurui/archive/2012/10/06/2712693.html

每天用心記錄一點點。內容也許不重要,但習慣很重要!

JDK 之 Java Bean 內省機制