參考書(shū)籍《瘋狂java》
反射的用處
反射能獲取對(duì)象的屬性笔咽,以及對(duì)象的屬性值鳍徽,甚至是私有的方法茬暇,這個(gè)一般是用在框架的首昔,或者是權(quán)限校驗(yàn),參數(shù)校驗(yàn)等框架的設(shè)計(jì)糙俗,反射在面試也比較常見(jiàn)勒奇,但是在實(shí)際的項(xiàng)目中,每個(gè)開(kāi)發(fā)者接觸的機(jī)會(huì)不多巧骚,一般都是大牛們?cè)谪?fù)責(zé)寫(xiě)這些赊颠,利用反射寫(xiě)一些通用組件等等,來(lái)解決發(fā)雜需求或者給其他開(kāi)發(fā)者提供組件
提問(wèn)
如何通過(guò)反射獲取UpdateCheckRequestType中子對(duì)象list里面的inspectionItemId以及checkDTO中的description
public class UpdateCheckRequestType {
private CheckDTO checkDTO;
private List<InspectionDTO> list;
}
public class CheckDTO {
private String id;
private String description;
public class InspectionDTO {
private String inspectionItemId;
private String inspectionValue;
首先要明確一點(diǎn)劈彪,在反射獲取屬性的過(guò)程中一定是先有class竣蹦,然后才有屬性,不多說(shuō)上代碼
public static void main(String[] args) {
// 準(zhǔn)備數(shù)據(jù)
CheckDTO dto = new CheckDTO();
dto.setDescription("123434");
InspectionDTO inspectionDTO = new InspectionDTO();
inspectionDTO.setInspectionItemId("123234");
List<InspectionDTO> list = new ArrayList<>();
list.add(inspectionDTO);
UpdateCheckRequestType type = new UpdateCheckRequestType();
type.setList(list);
type.setCheckDTO(dto);
}
有些伙伴會(huì)問(wèn)沧奴,直接new UpdateCheckRequestType不就完事了嗎痘括?為啥還要給里面的子對(duì)象賦值?你如果直接new出來(lái)滔吠,沒(méi)有賦值纲菌,拿到的子對(duì)象就是null,通過(guò)這個(gè)子對(duì)象去獲取子對(duì)象里面的屬性是獲取不到的疮绷,會(huì)拋出空指針異常翰舌,還是那句話,現(xiàn)有class再有屬性冬骚,既然class都是null椅贱,那么何來(lái)的屬性呢懂算?
// 獲取type的屬性
Field[] fields = type.getClass().getDeclaredFields();
System.out.println(fields[0].getName());
輸出結(jié)果
checkDTO
- 這里要說(shuō)下的是getDeclaredFields,getDeclaredField庇麦,getFields犯犁,getField
首先不包含s的獲取的是單個(gè)屬性的,需要提前知道屬性的名字女器,而且當(dāng)不存在時(shí)候會(huì)有異常拋出 - 不含有Declared的方法只能獲取共有屬性,而Declared可以獲取私有的屬性住诸,我們實(shí)體類中的屬性都是私有驾胆,當(dāng)然還有g(shù)etMethod等等規(guī)則和上面是一樣的
從這里看到我們已經(jīng)拿到了type中的子對(duì)象checkDTO,對(duì)type來(lái)說(shuō)checkDTO是其中的一個(gè)屬性贱呐,因此我們這里可以直接或取checkDTO,下面獲取checkDTO中的Description的值
// 獲取type的屬性
Field[] fields = type.getClass().getDeclaredFields();
// 設(shè)置私有屬性可以訪問(wèn)
fields[0].setAccessible(true);
// 獲取checkDTO的實(shí)際對(duì)象
Object value = fields[0].get(type);
System.out.println(value.toString());
如果缺少設(shè)置私有屬性允許訪問(wèn)這一步會(huì)拋出如下異常
Exception in thread "main" java.lang.IllegalAccessException: Class com.lightkits.mes.dto.equipment.FanShe can not access a member of class com.lightkits.mes.dto.equipment.UpdateCheckRequestType with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
at java.lang.reflect.Field.get(Field.java:390)
at com.lightkits.mes.dto.equipment.FanShe.main(FanShe.java:28)
輸出結(jié)果如下
CheckDTO(id=null, description=123434, equipmentId=null, remark=null, collector=null, taskStatus=null, taskNum=null)
OK丧诺,離目標(biāo)又進(jìn)了一步,接下來(lái)反射獲取description
Field[] fields1 = value.getClass().getDeclaredFields();
System.out.println(fields1[1].getName());
輸出結(jié)果
description
接下來(lái)獲取description的值 套路是一樣的
// 獲取checkDTO的實(shí)際對(duì)象
Object value = fields[0].get(type);
System.out.println(value.toString());
Field[] fields1 = value.getClass().getDeclaredFields();
System.out.println(fields1[1].getName());
fields1[1].setAccessible(true);
System.out.println(fields1[1].get(value));
值得注意的是在獲取子對(duì)象的屬性值的時(shí)候get里面放置的是子對(duì)象
輸出結(jié)果
123434
ok 既然有g(shù)et 那就必定有set
Object value = fields[0].get(type);
System.out.println(value.toString());
Field[] fields1 = value.getClass().getDeclaredFields();
System.out.println(fields1[1].getName());
fields1[1].setAccessible(true);
System.out.println(fields1[1].get(value));
fields1[1].set(value, "你好");
System.out.println(fields1[1].get(value));
輸出結(jié)果對(duì)比
123434
你好
set可以用來(lái)改變屬性值奄薇,這個(gè)在sqlhelp這個(gè)框架里面用到了驳阎,有興趣的可以去了解下,總之來(lái)說(shuō)get和set在反射中使用頻率比較高
如果想獲取list對(duì)象里面屬性對(duì)象的屬性值這個(gè)就和上面的套路是一樣的了馁蒂,直接上代碼
// 獲取type的屬性
Field[] fields = type.getClass().getDeclaredFields();
// 設(shè)置私有屬性可以訪問(wèn)
fields[1].setAccessible(true);
// 在強(qiáng)轉(zhuǎn)之前需要事先預(yù)判呵晚,否則會(huì)拋出異常
List<?> list1 = (List<?>)fields[1].get(type);
Object o = list1.get(0);
Field[] fields1 = o.getClass().getDeclaredFields();
這里是拿到子對(duì)象的屬性,能拿到屬性沫屡,就可以解決其他問(wèn)題饵隙,套路和上面是一樣
在項(xiàng)目中的多數(shù)情況下是要去拿屬性上的注解,根據(jù)屬性注解去做操作沮脖,使用的方法是
Field[] fields1 = o.getClass().getDeclaredFields();
Annotation[] annotations = fields[0].getAnnotations();
System.out.println(annotations.length);
System.out.println(annotations[0].annotationType());
結(jié)果如下
1
interface javax.validation.Valid