淺談Java內(nèi)省機(jī)制
概念
JavaBean
在實(shí)際編程中,我們常常需要一些用來(lái)包裝值對(duì)象的類,例如Student、 Employee、Order,這些 類中往往沒(méi)有業(yè)務(wù)方法,只是為了把需要處理的實(shí)體對(duì)象進(jìn)行封裝,有這樣的特征:
- 屬性都是私有的;
- 有無(wú)參的public構(gòu)造方法;
- 對(duì)私有屬性根據(jù)需要提供公有的getXxx方法以及setXxx方法;
比如:屬性名稱為name,則有g(shù)etName方法返回屬性name值, setName方法設(shè)置name值;注意方法的名稱通常是get或 set加上屬性名稱,并把屬性名稱的首字母大寫;這些方法稱為getters/setters;getters必須有返回值沒(méi)有方法參數(shù); setter值沒(méi)有返回值,有方法參數(shù);
例如下面的例子:

符合這些特征的類,被稱為JavaBean;
內(nèi)省
內(nèi)省(Inspector)機(jī)制就是基于反射的基礎(chǔ), Java語(yǔ)言對(duì)Bean類屬性、事件的一種缺省處理方法。
只要類中有g(shù)etXXX方法,或者setXXX方法,或者同時(shí)有g(shù)etXXX及setXXX方法,其中g(shù)etXXX方 法沒(méi)有方法參數(shù),有返回值; setXXX方法沒(méi)有返回值,有一個(gè)方法參數(shù);那么內(nèi)省機(jī)制就認(rèn)為 XXX為一個(gè)屬性;
例如下面代碼
Employee類中根本沒(méi)有聲明age屬性,僅僅是聲明了這樣的getter和setter.內(nèi)省機(jī)制就認(rèn)為age是屬性
package com.shixun.introspector;
public class Employee {
private String name;
private Double score;
// age將被內(nèi)省認(rèn)為是屬性
public int getAge(){
return 30;
}
// name將被內(nèi)省認(rèn)為是屬性
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// score將被內(nèi)省認(rèn)為是屬性
public Double getScore() {
return score;
}
public void setScore(Double score) {
this.score = score;
}
public static void main(String[] args) {
}
}
相關(guān)API
與Java內(nèi)省有關(guān)的主要類及接口有:
java.beans.Introspector類: 為獲得JavaBean屬性、事件、方法提供了標(biāo)準(zhǔn)方法;通常使用其中的getBeanInfo方法返回BeanInfo對(duì)象;Java.beans.BeanInfo接口:不能直接實(shí)例化,通常通過(guò)Introspector類返回該類型對(duì)象,提供了返回屬性描述符對(duì)象(PropertyDescriptor)、方法描述符對(duì)象(MethodDescriptor) 、 bean描述符(BeanDescriptor)對(duì)象的方法;Java.beans.PropertyDescriptor類:用來(lái)描述一個(gè)屬性,該屬性有g(shù)etter及setter方法;
可以使用PropertyDescriptor類的方法獲取屬性相關(guān)的信息,例如getName方法返回屬性的名字:
PropertyDescriptor類中定義了方法可以獲取該屬性的getter和setter方法
| 方法 | 方法描述 |
|---|---|
| Method getReadMethod() | 回屬性對(duì)應(yīng)的getter方法對(duì)象; |
| Method getWriteMethod() | 回屬性對(duì)應(yīng)的setter方法對(duì)象; |
下面我們來(lái)用代碼深入探究一下:
代碼案例:獲取屬性相關(guān)信息
Employee如上面代碼所示,繼續(xù)編寫主函數(shù)進(jìn)行測(cè)試
首先用BeanInfo接口獲取BeanInfo的對(duì)象,再通過(guò)BeanInfo對(duì)象獲取PropertyDescriptor屬性描述
//獲取BeanInfo的對(duì)象
BeanInfo employeeBeanInfo = Introspector.getBeanInfo(Employee.class);
//通過(guò)BeanInfo對(duì)象獲取PropertyDescriptor屬性描述
PropertyDescriptor[] propertyDescriptors = employeeBeanInfo.getPropertyDescriptors();
System.out.println("通過(guò)Inspector內(nèi)省機(jī)制獲取JavaBean屬性======= 打印所有信息 ====================");
Arrays.stream(propertyDescriptors).forEach(f->{
System.out.println("====================================");
System.out.println("屬性名:"+f.getName());
System.out.println("類型:"+f.getPropertyType());
System.out.println("get方法:"+f.getReadMethod());
System.out.println("set方法:"+f.getWriteMethod());
});
// 或者用增強(qiáng)for
System.out.println("通過(guò)Inspector內(nèi)省機(jī)制獲取JavaBean屬性======= 打印所有信息 ====================");
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
System.out.println("====================================");
System.out.println("名字:" + propertyDescriptor.getName());
System.out.println("類型:" + propertyDescriptor.getPropertyType());
System.out.println("get方法:" + propertyDescriptor.getReadMethod());
System.out.println("set方法:" + propertyDescriptor.getWriteMethod());
}
運(yùn)行結(jié)果如下:

我們也可以通過(guò)反射調(diào)用這里獲取的get或set方法
//創(chuàng)建Employee的對(duì)象
Class<?> clazz = Class.forName("com.shixun.introspector.Employee");
Object employee = clazz.newInstance();
//遍歷屬性描述對(duì)象
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
//打印屬性名稱
System.out.println(propertyDescriptor.getName());
//判斷屬性名稱是不是name
if (propertyDescriptor.getName().equals("name")) {
//setter方法
Method writeMethod = propertyDescriptor.getWriteMethod();
//調(diào)用setName方法
writeMethod.invoke(employee, "jack");
//getter方法
Method readMethod = propertyDescriptor.getReadMethod();
//調(diào)用getName方法
Object nameValue = readMethod.invoke(employee);
System.out.println("name屬性的值為:" + nameValue);
}
//判斷屬性名稱是否為score
if (propertyDescriptor.getName().equals("score")) {
//setter方法
Method scoreWriteMethod = propertyDescriptor.getWriteMethod();
//調(diào)用setScore方法
scoreWriteMethod.invoke(employee, new Double(3000));
//getter方法
Method scoreReadMethod = propertyDescriptor.getReadMethod();
Object scoreValue = scoreReadMethod.invoke(employee);
System.out.println("score屬性的值為:" + scoreValue);
}
}
System.out.println("當(dāng)前對(duì)象的信息:"+employee.toString());
運(yùn)行結(jié)果如下所示:

全部代碼附在最下方?。。。。?!
內(nèi)省屬性的注意事項(xiàng)
- 很多框架都使用了內(nèi)省機(jī)制檢索對(duì)象的屬性,定義屬性名字時(shí),名字最好起碼以兩個(gè)小寫字母開(kāi)頭,例如stuName,而不要使用sName,某些情況下,可能會(huì)導(dǎo)致檢索屬性失敗;
- 內(nèi)省機(jī)制檢索屬性時(shí),是根據(jù)getter和setter方法確認(rèn)屬性名字,而不是根據(jù)類里聲明的成員變量名稱決定;
完整代碼
package com.shixun.introspector;
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.Arrays;
public class Employee {
private String name;
private Double score;
// age將被內(nèi)省認(rèn)為是屬性
public int getAge() {
return 30;
}
// name將被內(nèi)省認(rèn)為是屬性
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// score將被內(nèi)省認(rèn)為是屬性
public Double getScore() {
return score;
}
public void setScore(Double score) {
this.score = score;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", score=" + score +
'}';
}
public static void main(String[] args) throws ClassNotFoundException, IntrospectionException, IllegalAccessException, InstantiationException, InvocationTargetException {
//獲取BeanInfo的對(duì)象
BeanInfo employeeBeanInfo = Introspector.getBeanInfo(Employee.class);
//通過(guò)BeanInfo對(duì)象獲取PropertyDescriptor屬性描述
PropertyDescriptor[] propertyDescriptors = employeeBeanInfo.getPropertyDescriptors();
// System.out.println("通過(guò)Inspector內(nèi)省機(jī)制獲取JavaBean屬性======= 打印所有信息 ====================");
// Arrays.stream(propertyDescriptors).forEach(f->{
// System.out.println("====================================");
// System.out.println("屬性名:"+f.getName());
// System.out.println("類型:"+f.getPropertyType());
// System.out.println("get方法:"+f.getReadMethod());
// System.out.println("set方法:"+f.getWriteMethod());
// });
//
//
//
// System.out.println("通過(guò)Inspector內(nèi)省機(jī)制獲取JavaBean屬性======= 打印所有信息 ====================");
//
// for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
// System.out.println("名字:" + propertyDescriptor.getName());
// System.out.println("類型:" + propertyDescriptor.getPropertyType());
// System.out.println("get方法:" + propertyDescriptor.getReadMethod());
// System.out.println("set方法:" + propertyDescriptor.getWriteMethod());
// }
//創(chuàng)建Employee的對(duì)象
Class<?> clazz = Class.forName("com.shixun.introspector.Employee");
Object employee = clazz.newInstance();
//遍歷屬性描述對(duì)象
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
//打印屬性名稱
System.out.println(propertyDescriptor.getName());
//判斷屬性名稱是不是name
if (propertyDescriptor.getName().equals("name")) {
//setter方法
Method writeMethod = propertyDescriptor.getWriteMethod();
//調(diào)用setName方法
writeMethod.invoke(employee, "jack");
//getter方法
Method readMethod = propertyDescriptor.getReadMethod();
//調(diào)用getName方法
Object nameValue = readMethod.invoke(employee);
System.out.println("name屬性的值為:" + nameValue);
}
//判斷屬性名稱是否為score
if (propertyDescriptor.getName().equals("score")) {
//setter方法
Method scoreWriteMethod = propertyDescriptor.getWriteMethod();
//調(diào)用setScore方法
scoreWriteMethod.invoke(employee, new Double(3000));
//getter方法
Method scoreReadMethod = propertyDescriptor.getReadMethod();
Object scoreValue = scoreReadMethod.invoke(employee);
System.out.println("score屬性的值為:" + scoreValue);
}
}
System.out.println("當(dāng)前對(duì)象的信息:"+employee.toString());
}
}
到此這篇關(guān)于淺談Java內(nèi)省機(jī)制的文章就介紹到這了,更多相關(guān)Java內(nèi)省機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java判斷integer是否為空的詳細(xì)過(guò)程
在java編寫過(guò)程中,我們會(huì)使用到各種各樣的表達(dá)式,在使用表達(dá)式的過(guò)程中,有哪些安全問(wèn)題需要我們注意的呢?對(duì)java判斷integer是否為空相關(guān)知識(shí)感興趣的朋友一起來(lái)看看吧2023-02-02
Spring Boot中單例類實(shí)現(xiàn)對(duì)象的注入方式
這篇文章主要介紹了Spring Boot中單例類實(shí)現(xiàn)對(duì)象的注入方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
Dubbo異步調(diào)用的實(shí)現(xiàn)介紹
dubbo默認(rèn)使用同步的方式調(diào)用。但在有些特殊的場(chǎng)景下,我們可能希望異步調(diào)用dubbo接口,從而避免不必要的等待時(shí)間,這時(shí)候我們就需要用到異步。那么dubbo的異步是如何實(shí)現(xiàn)的呢?下面就來(lái)看看這個(gè)問(wèn)題2022-09-09
Java 基礎(chǔ):string中的compareTo方法
這篇文章主要介紹了Java 基礎(chǔ):string中的compareTo方法,文章圍繞string中的compareTo方法的相關(guān)資料展開(kāi)文章詳細(xì)內(nèi)容,希望對(duì)待大家有所幫助2021-12-12
springboot中請(qǐng)求路徑配置在配置文件中詳解
這篇文章主要介紹了springboot中請(qǐng)求路徑配置在配置文件中,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
淺析SpringBoot2.4 靜態(tài)資源加載問(wèn)題
這篇文章主要介紹了SpringBoot2.4 靜態(tài)資源加載問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01

