java 有哪些反射机制_Java 的反射机制你了解多少?
不知道多少次聽(tīng)說(shuō)過(guò)了Java反射機(jī)制的使用,比如:Spring 框架如何實(shí)例化IoC容器中的Bean,編碼過(guò)程中如何動(dòng)態(tài)的清理對(duì)象中的字段信息等等。工作中只是聽(tīng)說(shuō)、看同事們編碼實(shí)踐,但是自己卻只是概念上的認(rèn)識(shí),淺顯粗略,今天就補(bǔ)一下反射的知識(shí)點(diǎn),自己欠下的債,遲早是要還的。
一. 什么是反射?
在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類(lèi),都能夠獲取到這個(gè)類(lèi)的所有屬性和方法,對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)方法和屬性(包括私有的方法和屬性),這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象方法的功能就稱(chēng)為java語(yǔ)言的反射機(jī)制。通俗點(diǎn)講,通過(guò)反射,該類(lèi)對(duì)我們來(lái)說(shuō)是完全透明的,想要獲取任何東西都可以。
想要使用反射機(jī)制,就必須要先獲取到該類(lèi)的字節(jié)碼文件對(duì)象(.class),通過(guò)字節(jié)碼文件對(duì)象,就能夠通過(guò)該類(lèi)中的方法獲取到我們想要的所有信息(方法,屬性,類(lèi)名,父類(lèi)名,實(shí)現(xiàn)的所有接口等等),每一個(gè)類(lèi)對(duì)應(yīng)著一個(gè)字節(jié)碼文件也就對(duì)應(yīng)著一個(gè)Class類(lèi)型的對(duì)象,也就是字節(jié)碼文件對(duì)象。
獲取類(lèi)的字節(jié)碼文件對(duì)象有三種方式:
Class clazz1 = Class.forName("全限定類(lèi)名"); // 通過(guò)Class類(lèi)中的靜態(tài)方法forName,直接獲取到一個(gè)類(lèi)的字節(jié)碼文件對(duì)象,此時(shí)該類(lèi)還是源文件階段,并沒(méi)有變?yōu)樽止?jié)碼文件。
Class clazz2 = User.class; // 當(dāng)類(lèi)被加載成.class文件時(shí),此時(shí)Person類(lèi)變成了.class,在獲取該字節(jié)碼文件對(duì)象,也就是獲取自己, 該類(lèi)處于字節(jié)碼階段。
User user = new User();
Class clazz3 = p.getClass(); // 通過(guò)類(lèi)的實(shí)例獲取該類(lèi)的字節(jié)碼文件對(duì)象,該類(lèi)處于創(chuàng)建對(duì)象階段
有了字節(jié)碼文件對(duì)象才能獲得類(lèi)中所有的信息,我們?cè)谑褂梅瓷浍@取信息時(shí),也要考慮使用上面哪種方式獲取字節(jié)碼對(duì)象合理,視不同情況而定。下面介紹Class類(lèi)的功能。
二. 反射機(jī)制能夠動(dòng)態(tài)獲取類(lèi)的哪些信息?
2.1 通過(guò)字節(jié)碼對(duì)象創(chuàng)建實(shí)例對(duì)象
// 通過(guò)字節(jié)碼對(duì)象創(chuàng)建實(shí)例對(duì)象
Class> userClz1 = Class.forName("com.base.reflect.entity.User");
User user1 = (User) userClz1.newInstance();
log.info("userClz1 instance = {}", user1);
Class> userClz2 = User.class;
User user2 = (User) userClz1.newInstance();
log.info("userClz1 instance = {}", user2);
2.2 獲取指定構(gòu)造器方法,constructor 有參無(wú)參創(chuàng)建實(shí)例
// 獲取指定構(gòu)造器,有參無(wú)參構(gòu)造實(shí)例對(duì)象
Class> userClz3 = Class.forName("com.base.reflect.entity.User");
Constructor> constructor1 = userClz3.getConstructor();
User user3 = (User) constructor1.newInstance();
log.info("constructor1 user3 = {}", user3);
Constructor> constructor2 = userClz3.getConstructor(String.class, String.class, String.class, Date.class, String.class, Date.class);
User user4 = (User) constructor2.newInstance("admin", "123456", "admin", new Date(), "admin", new Date());
log.info("constructor user4 = {}", constructor2);
總結(jié)上面創(chuàng)建實(shí)例對(duì)象:
a)Class類(lèi)的 newInstance() 方法是使用該類(lèi)無(wú)參的構(gòu)造函數(shù)創(chuàng)建對(duì)象;
b)可以調(diào)用Class類(lèi)的?getConstructor(Class>... parameterTypes) 方法獲取一個(gè)指定參數(shù)的構(gòu)造函數(shù),然后再調(diào)用Constructor類(lèi)的newInstance(value1, value2 ...)方法創(chuàng)建對(duì)象;
獲取類(lèi)中全部構(gòu)造方法:
// 獲取當(dāng)前類(lèi)中 public 類(lèi)型的構(gòu)造函數(shù)
Constructor>[] constructors = userClz3.getConstructors();
// 獲取當(dāng)前類(lèi)中 public protected default private 類(lèi)型的構(gòu)造函數(shù)
Constructor>[] declaredConstructors = userClz3.getDeclaredConstructors();
2.3 獲取指定的方法,動(dòng)態(tài)調(diào)用方法
// 動(dòng)態(tài)獲取類(lèi)中的方法
User user5 = new User("lisi", "123456", "lisi", new Date(), "lisi", new Date());
log.info("user5 = {}", user5);
// 獲取User類(lèi)中的 setParams 方法,并指定方法中的參數(shù)類(lèi)型
Method method = user5.getClass().getMethod("setParams", String.class, String.class);
// 執(zhí)行方法,傳遞參數(shù)【指明運(yùn)行哪個(gè)對(duì)象中的哪個(gè)方法】
method.invoke(user5,"hello", "123123");
log.info("user5 = {}", user5);
輸出結(jié)果:
user5 = User(username=lisi, password=123456, createBy=lisi, createTime=Thu Oct 22 17:21:52 CST 2020, updateBy=lisi, updateTime=Thu Oct 22 17:21:52 CST 2020)
user5 = User(username=hello, password=123123, createBy=lisi, createTime=Thu Oct 22 17:21:52 CST 2020, updateBy=lisi, updateTime=Thu Oct 22 17:21:52 CST 2020)
總結(jié)上面動(dòng)態(tài)調(diào)用類(lèi)中的方法:
Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...) 方法可以獲取類(lèi)中的指定方法,如果為私有方法,則需要打開(kāi)一個(gè)私有方法權(quán)限。
setAccessible(true);用 invoke(Object, Object...) 可以調(diào)用該方法;
獲取類(lèi)中全部方法:
// 獲取當(dāng)前類(lèi)中 public 類(lèi)型的方法
Method[] methods = User.class.getMethods();
// 獲取當(dāng)前類(lèi)中 public protected default private 類(lèi)型的方法
Method[] declaredMethods = User.class.getDeclaredMethods();
2.4 獲取指定的字段,動(dòng)態(tài)設(shè)置對(duì)象中字段的值
// 動(dòng)態(tài)獲取對(duì)象中的 Field
User user6 = new User("zhangsan", "123456", "zhangsan", new Date(), "zhangsan", new Date());
log.info("user6 = {}", user1);
clearFields(user6, "createBy", "createTime", "updateBy", "updateTime");
log.info("user6 = {}", user6);
// 清理對(duì)象中的字段信息
private static void clearFields(User user1, String... params) throws IllegalAccessException, NoSuchFieldException {
for (String param : params) {
Field field = user1.getClass().getDeclaredField(param);
field.setAccessible(true);
Object obj = field.get(user1);
log.info("obj = {}", obj);
field.set(user1, null);
}
}
輸出結(jié)果:
user6 = User(username=zhangsan, password=123456, createBy=zhangsan, createTime=Thu Oct 22 17:33:18 CST 2020, updateBy=zhangsan, updateTime=Thu Oct 22 17:33:18 CST 2020)
obj = zhangsan
obj = Thu Oct 22 17:33:18 CST 2020
obj = zhangsan
user6 = User(username=zhangsan, password=123456, createBy=null, createTime=null, updateBy=null, updateTime=null)
獲取類(lèi)中全部字段信息:
// 獲取當(dāng)前類(lèi)中 public 類(lèi)型的字段
Field[] fields = User.class.getFields();
// 獲取當(dāng)前類(lèi)中 public protected default private 類(lèi)型的字段
Field[] fields = User.class.getDeclaredFields();
使用場(chǎng)景:在使用 MyBatis 攔截器?Interceptor 對(duì)應(yīng)用添加、更新對(duì)象時(shí),需要重新設(shè)置 createBy createTime updateBy updateTime 字段信息,動(dòng)態(tài)的清理一些字段信息,然后重新設(shè)置。
總結(jié)
以上是生活随笔為你收集整理的java 有哪些反射机制_Java 的反射机制你了解多少?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java spring工作原理_Spri
- 下一篇: java常见_Java 常用类