大多數人不知道的Java知識 - Introspector(內省器)和 PropertyDescriptor(屬性描述器)

聆聽 沉澱 傳播 … 關注微信公衆號【Java之言】,助你放棄編程之路!java


1、Introspector 簡介

官方介紹:

The Introspector class provides a standard way for tools to learn about the properties, events, and methods supported by a target Java Bean.

For each of those three kinds of information, the Introspector will separately analyze the bean’s class and superclasses looking for either explicit or implicit information and use that information to build a BeanInfo object that comprehensively describes the target bean.web

java.beans.Introspector,即內省器。爲訪問Java Bean的屬性事件方法提供了標準的處理方法。

對於Java Bean 的這3種信息,Introspector 內省器會分別地尋找分析 Java Bean 以及它的父類的 包括顯示和隱式的信息,而後構建一個全面描述此Java Bean 的 BeanInfo 對象。編程

在Java中,JavaBean 是一種特殊的類,主要用於傳遞數據信息。例如DTOVO等,咱們在業務或者模塊之間傳遞信息,能夠將信息封裝到JavaBean中。
既然封裝到JavaBean中,那就會有設置(setter)讀取(getter)JavaBean中屬性等操做。Introspector能夠幫咱們作到這件事,不過要注意,JavaBean中的getter和setter等方法要遵循某種規範。

底層是充分利用了反射的原理操做類屬性。微信

package com.nobody;

/** * @Description JavaBean類 * @Author Mr.nobody * @Date 2021/1/24 * @Version 1.0 */
public class Person { 
 
   
    private String id;
    private String name;
    private int age;
    
	public Person(String id, String name, int age) { 
 
   
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public String getId() { 
 
   
        return id;
    }

    public void setId(String id) { 
 
   
        this.id = id;
    }

    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;
    }
}
// 獲取Person類的BeanInfo
BeanInfo beanInfo = Introspector.getBeanInfo(Person.class);

2、BeanInfo 簡介

官方介紹:

Use the BeanInfo interface to create a BeanInfo class and provide explicit information about the methods, properties, events, and other features of your beans.

簡而言之,java.beans.BeanInfo 接口可以建立一個BeanInfo對象,這個對象能提供關於JavaBean的方法屬性事件以及其餘特徵的明確信息。 其主要方法以下:dom

  • getPropertyDescriptors():得到屬性描述器。
  • getBeanDescriptor():得到對象描述器。
  • getMethodDescriptors:得到方法描述器。

3、PropertyDescriptor 簡介

官方介紹:

A PropertyDescriptor describes one property that a Java Bean exports via a pair of accessor methods.ide

java.beans.PropertyDescriptor,即屬性描述器。表示 Java Bean 經過存儲器方法導出的一個屬性。你能夠簡單認爲PropertyDescriptor裏面封裝了JavaBean的其中一個屬性的相關信息(例如屬性名,屬性類型,get和set等方法)。其主要方法以下:svg

  • getName():得到屬性名。
  • getPropertyType():得到屬性類型。
  • getReadMethod():得到用於讀取屬性值的方法。
  • getWriteMethod():得到用於寫入屬性值的方法。
  • setReadMethod(Method readMethod):設置用於讀取屬性值的方法。
  • setWriteMethod(Method writeMethod):設置用於寫入屬性值的方法。
Person person = new Person(UUID.randomUUID().toString(), "Mr_nobody", 18);
BeanInfo beanInfo = Introspector.getBeanInfo(Person.class);
PropertyDescriptor namePropertyDescriptor = new PropertyDescriptor("name", Person.class);
System.out.println("屬性名:" + namePropertyDescriptor.getName());
System.out.println("屬性類型:" + namePropertyDescriptor.getPropertyType());

Method namePropertyDescriptorReadMethod = namePropertyDescriptor.getReadMethod();
Object personName = namePropertyDescriptorReadMethod.invoke(person, null);
System.out.println("before personName:" + personName);

Method namePropertyDescriptorWriteMethod = namePropertyDescriptor.getWriteMethod();
namePropertyDescriptorWriteMethod.invoke(person, "Tony");
personName = namePropertyDescriptorReadMethod.invoke(person, null);
System.out.println("after personName:" + personName);

// 輸出結果:
屬性名:name
屬性類型:class java.lang.String
before personName:Mr_nobody
after personName:Tony

4、BeanDescriptor 簡介

官方介紹:

A BeanDescriptor provides global information about a 「bean」, including its Java class, its displayName, etc.

This is one of the kinds of descriptor returned by a BeanInfo object, which also returns descriptors for properties, method, and events.ui

java.beans.BeanDescriptor,即對象描述器。它提供了一個JavaBean的全局信息,例如JavaBean的類型,類名等信息。它是BeanInfo對象返回的一種描述器,其餘描述器還有屬性描述器,方法描述器,事件描述器等。this

BeanInfo beanInfo = Introspector.getBeanInfo(Person.class);
BeanDescriptor beanDescriptor = beanInfo.getBeanDescriptor();
// BeanDescriptor beanDescriptor = new BeanDescriptor(Person.class);
System.out.println(beanDescriptor.getBeanClass());
System.out.println(beanDescriptor.getName());

// 輸出結果:
class com.nobody.Person
Person

5、案例實踐

通常,使用最多的是 IntrospectorBeanInfoPropertyDescriptor,這三者結合起來使用。
url

需求:假設咱們有一個Person對象,須要將此對象轉換爲Map對象。

分析:Map的特徵是key-value鍵值對,則須要遍歷Person對象的每一個屬性名以及對應的值,放入Map中便可。

package com.nobody;

import java.beans.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/** * @Description * @Author Mr.nobody * @Date 2021/1/24 * @Version 1.0 */
public class Demo { 
 
   
    public static void main(String[] args) throws Exception { 
 
   
        Person person = new Person(UUID.randomUUID().toString(), "Mr_nobody", 18);
        System.out.println(beanToMap(person));

    }

    private static Map<String, Object> beanToMap(Object object)
            throws IntrospectionException, InvocationTargetException, IllegalAccessException { 
 
   
        // 須要返回的Map
        Map<String, Object> map = new HashMap<>();
        // 獲取BeanInfo對象
        BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
        // 獲取全部屬性描述器
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        // 遍歷每個屬性描述器
        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { 
 
   
            // 屬性名
            String name = propertyDescriptor.getName();
            // 過濾class屬性
            if (!Objects.equals("class", name)) { 
 
   
                // 獲取屬性的get方法
                Method readMethod = propertyDescriptor.getReadMethod();
                // 獲取屬性的值
                Object value = readMethod.invoke(object);
                map.put(name, value);
            }
        }
        return map;
    }
}
// 輸出結果
{ 
 
   name=Mr_nobody, id=57e496c6-87bb-4750-b176-5ef4bfb58b35, age=18}

若是咱們將Person類的getId()方法換一個方法名,或者去除此方法,會發生什麼呢? 假如咱們將getId()方法名改成getUid(),再執行上面的案例。

public String getUid() { 
 
   
    return id;
}
Exception in thread "main" java.lang.NullPointerException
	at com.nobody.Demo.beanToMap(Demo.java:38)
	at com.nobody.Demo.main(Demo.java:17)

程序報錯了,這就是前面我說的JavaBean的get和set方法爲何要遵循某種規則

緣由很簡單,由於在取得id這個屬性的屬性描述器時,咱們獲取到了屬性名,可是由於get方法沒有遵循規則,因此調用getReadMethod()獲取不到方法,因此出現空指針。

因此,在使用內省器和屬性描述器的時候,要注意,將屬性的get和set方法名寫標準便可,即 get + 屬性名()get + 屬性名()

本文同步分享在 博客「Μr.ηobοdy」(CSDN)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索