Java中的反射機(jī)制基本運(yùn)用詳解
Java中的反射機(jī)制基本運(yùn)用
看完反射可以了解一下注解
注解annotation://www.dbjr.com.cn/article/221276.htm
1、什么是反射(reflect)
反射是java的動態(tài)機(jī)制,它允許將對象的實(shí)例化,方案的調(diào)用,屬性的操作等從編碼期確定轉(zhuǎn)移到程序運(yùn)行期確定。
反射能大大提高代碼的靈活度。但同時(shí)也帶來了更多的系統(tǒng)開銷和較慢的運(yùn)行效率,因此程序不能過度依賴反射。
2、反射機(jī)制提供的功能
- 在運(yùn)行時(shí)判斷任意一個(gè)對象所屬的類
- 在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對象(實(shí)例化)
- 在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法
- 在運(yùn)行時(shí)調(diào)用任意一個(gè)對象的方法——?jiǎng)討B(tài)代理
3、反射->獲取類對象
在開始之前創(chuàng)建一個(gè)實(shí)體類,用于測試反射機(jī)制
package reflect_text; /** * 用于測試反射機(jī)制 * * @author Akio * @Create 2021/8/14 10:37 */ public class Person { private String name = "劉瑜澄";//設(shè)置初始值 private int age = 22; public Person() {//無參構(gòu)造 } public Person(String name, int age) {//有參構(gòu)造 this.name = name; this.age = age; } public void sayHello() {//無參方法 System.out.println(name + ":使用sayHello方法"); } public void sayGoodBye() {//無參方法 System.out.println(name + ":使用sayGoodBye方法"); } public void say(String info) {//有參方法 System.out.println(name + ":" + info); } public void say(String info, int sum) {//有參方法(重載say方法) for (int i = 0; i < sum; i++) { System.out.println(name + ":" + info); } } private void privateMethod() {//私有方法 System.out.println(name + ":這是一個(gè)私有方法"); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
以上這個(gè)用于測試反射的實(shí)體類創(chuàng)建成功后,先學(xué)習(xí)反射中是如何獲取類對象的。
反射的第一步就是要獲取操作類的類對象,即一個(gè)Class的實(shí)例,JVM中每個(gè)被加載的類有且只有一個(gè)類對象與之對應(yīng),獲取到這個(gè)類對象后我們就可以通過這個(gè)類對象來了解該類的一切信息(類名、有哪些方法、屬性等等) 以便在程序運(yùn)行期間通過反射機(jī)制進(jìn)行相關(guān)操作
這里介紹三種獲取類對象的方式:
(包名.)類名.class
Class personClass = reflect_text.Person.class; Class intClass = int.class;
這種方式最直接,但是由于是靠硬編碼形式寫死(編譯期間已經(jīng)確定),因此不夠靈活。但是需要注意,基本類型(int\double等)只能通過這種方式獲取類對象
Class.forName(String className)
Class personClass = Class.forName("reflect_text.Person"); Class stringClass = Class.forName("java.lang.String");
這種方式較為常用,遵循運(yùn)行期綁定。
類加載器ClassLoader
Class stringClass = ClassLoader.getSystemClassLoader().loadClass("java.lang.String"); Class personClass = ClassLoader.getSystemClassLoader().loadClass("reflect_text.Person");
在這一節(jié)中介紹幾個(gè)簡單的方法:
getName() 獲取類的完全限定名:包名.類名 getSimpleName() 僅僅獲取類名 getMethods() 返回一個(gè)Method數(shù)組,獲取class所表示的類的所有公開方法(包含從超類中繼承的方法)
例子:
Scanner scanner = new Scanner(System.in); Class cls = Class.forName(scanner.nextLine());//運(yùn)行期綁定 String name = cls.getName();//獲取類的完全限定名:包名.類名 System.out.println("完全限定名 = " + name); name = cls.getSimpleName();//僅獲取類名 System.out.println("僅類名 = " + name); Method[] methods = cls.getMethods(); for (Method m : methods) { System.out.print(m.getName()+"\t"); }
4、反射->利用無參構(gòu)造實(shí)例化對象
Class類中提供了一個(gè)方法newInstance()來實(shí)例化,該方法要求此類必須具有無參構(gòu)造器,它是通過無參構(gòu)造器實(shí)例化對象的。
Person person = new Person(); //1獲取要實(shí)例化的類的類對象 Scanner scanner = new Scanner(System.in); System.out.println("請輸入類名:"); Class cls = Class.forName(scanner.nextLine()); /* 通過Class提供的方法newInstance()來實(shí)例化 該方法要求此類必須具有無參構(gòu)造器,它是通過無參構(gòu)造器實(shí)例化對象的 */ Object obj = cls.newInstance(); System.out.println("obj = " + obj);
5、反射->利用有參構(gòu)造實(shí)例化對象
getConstructor() //獲取無參構(gòu)造器,可以利用無參構(gòu)造器實(shí)例化對象,但這個(gè)方法對于使用無參構(gòu)造器實(shí)例化對象可有可無 getConstructor(類對象) //通過類對象獲取特定的構(gòu)造器,該參數(shù)列表是根據(jù)特定構(gòu)造器的參數(shù)列表類型來決定的,如 getConstructor(String.class, int.class) 即為調(diào)用Person類中兩個(gè)參數(shù)的有參構(gòu)造器 public Person(String name, int age) {//有參構(gòu)造 this.name = name; this.age = age; }
舉例
//加載類對象 Class cls = Class.forName("reflect.Person"); //通過類對象獲取特定的構(gòu)造器 Constructor c = cls.getConstructor(String.class, int.class); Object o = c.newInstance("流年", 21);//實(shí)例化 System.out.println(o);
結(jié)果可知初始值已經(jīng)被修改
6、反射->調(diào)用無參方法
getMethod(String MethodName) 獲取類對象的MethodName方法,返回值類型為Method invoke(Object object) 執(zhí)行object對象的某方法
舉例
//一般調(diào)用方法的做法------------------- Person p = new Person();//實(shí)例化對象 p.sayHello();//調(diào)用該對象方法 //反射機(jī)制調(diào)用方法----------------------- //1、實(shí)例化對象 Class cls = Class.forName("reflect_text.Person"); Object o = cls.newInstance(); //2、調(diào)用o的sayHello方案 //2.1通過Class獲取Person的sayHello方法 Method method = cls.getMethod("sayHello"); //2.2調(diào)用o的該方法 method.invoke(o);//等效于一般方法中的o.sayHello()
可見兩種操作均能達(dá)到一樣的效果
7、反射->調(diào)用有參方法
getMethod(String MethodName, 類對象) 獲取類對象的MethodName有參方法,并傳入對應(yīng)參數(shù)類型的類對象,返回值類型為Method
舉例
//一般調(diào)用有參方法------------------------ Person p = new Person(); p.say("七夕快樂~"); p.say("七夕快樂~",3); //反射機(jī)制調(diào)用有參方法--------------------- Class cls = Class.forName("reflect_text.Person"); Object o = cls.newInstance(); //調(diào)用say(String info)方法 Method m1 = cls.getMethod("say", String.class); m1.invoke(o, "春節(jié)快樂~"); //調(diào)用say(String info, int sum) Method m2 = cls.getMethod("say", String.class, int.class); m2.invoke(o,"春節(jié)快樂~",3);
通過結(jié)果可以看到,效果都是一樣的
8、反射->訪問私有方法
注意:反射訪問私有的方法,但是會破壞類的封裝性
getDeclaredMethod(String MethodName) 可以僅獲取此類定義的所有方法,包含私有方法 setAccessible(boolean flag) 開啟私有方法的訪問權(quán)限
舉例
//正常情況下,在本類中不可以訪問外部的私有方法 //但在反射機(jī)制中可行 Class cls = Class.forName("reflect_text.Person"); Object o = cls.newInstance(); Method method = cls.getDeclaredMethod("privateMethod"); method.setAccessible(true);//打開訪問權(quán)限 method.invoke(o);
9、反射->類加載路徑
加載資源時(shí)常用相對路徑,之前學(xué)習(xí)的相對路徑./由于運(yùn)行環(huán)境不同,位置并非固定,因此實(shí)際開發(fā)中使用較少。
接下來介紹,在開發(fā)中常用的類加載路徑
常用的路徑通常為類的加載路徑,有兩個(gè):
1:類對象.getResource()
與當(dāng)前類所處同一目錄
2:類加載器.getResource()
類加載路徑,類的package定義中根包位置。
例如:有一個(gè)類: package reflect_text; public class WebServer{ …… } 在WebServer類中,當(dāng)我們使用上述兩種方式獲取路徑時(shí)他們的對應(yīng)位置為: WebServer.class.getResource() 當(dāng)前WebServer所在的目錄(編譯后的class文件所在目錄) WebServer.class.getClassLoader().getResource() 則是在WebServer的包的最上級,即com包的上一級
package reflect_text; public class ReflectDemo { File dir = new File(ReflectDemo.class.getResource(".").toURI()); System.out.println("dir = " + dir); //dir = D:\ClassCode\JavaSE_API\out\production\JavaSE_API\reflect File dir2 = new File(ReflectDemo.class.getClassLoader().getResource(".").toURI()); System.out.println("dir2 = " + dir2); //dir2 = D:\ClassCode\JavaSE_API\out\production\JavaSE_API }
總結(jié)
本片文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
基于SpringIOC創(chuàng)建對象的四種方式總結(jié)
這篇文章主要介紹了基于SpringIOC創(chuàng)建對象的四種方式總結(jié),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06面試總結(jié):秒殺設(shè)計(jì)、AQS 、synchronized相關(guān)問題
Java語言的關(guān)鍵字,當(dāng)它用來修飾一個(gè)方法或者一個(gè)代碼塊的時(shí)候,能夠保證在同一時(shí)刻最多只有一個(gè)線程執(zhí)行該段代碼。本文給大家介紹java中 synchronized的用法,對本文感興趣的朋友一起看看吧2021-06-06Android中Parcelable的作用實(shí)例解析
這篇文章主要介紹了Android中Parcelable的作用,對于Android初學(xué)者有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2014-08-0810個(gè)SpringBoot參數(shù)驗(yàn)證你需要知道的技巧分享
參數(shù)驗(yàn)證很重要,是平時(shí)開發(fā)環(huán)節(jié)中不可少的一部分,那么在Spring?Boot應(yīng)用中如何做好參數(shù)校驗(yàn)工作呢,本文提供了10個(gè)小技巧,你知道幾個(gè)呢2023-03-03mybatis spring配置SqlSessionTemplate的使用方式
這篇文章主要介紹了mybatis spring配置SqlSessionTemplate的使用方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08