您好,登錄后才能下訂單哦!
這篇文章主要講解了“Java中的反射機(jī)制的基本運(yùn)用”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Java中的反射機(jī)制的基本運(yùn)用”吧!
Java中的反射機(jī)制基本運(yùn)用
1、什么是反射(reflect)
2、反射機(jī)制提供的功能
3、反射->獲取類對(duì)象
4、反射->利用無(wú)參構(gòu)造實(shí)例化對(duì)象
5、反射->利用有參構(gòu)造實(shí)例化對(duì)象
6、反射->調(diào)用無(wú)參方法
7、反射->調(diào)用有參方法
8、反射->訪問私有方法
9、反射->類加載路徑
看完反射可以了解一下注解
注解annotation://www.kemok4.com/article/221276.htm
反射是java的動(dòng)態(tài)機(jī)制,它允許將對(duì)象的實(shí)例化,方案的調(diào)用,屬性的操作等從編碼期確定轉(zhuǎn)移到程序運(yùn)行期確定。
反射能大大提高代碼的靈活度。但同時(shí)也帶來(lái)了更多的系統(tǒng)開銷和較慢的運(yùn)行效率,因此程序不能過度依賴反射。
在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類
在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象(實(shí)例化)
在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法
在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法——?jiǎng)討B(tài)代理
在開始之前創(chuàng)建一個(gè)實(shí)體類,用于測(cè)試反射機(jī)制
package reflect_text; /** * 用于測(cè)試反射機(jī)制 * * @author Akio * @Create 2021/8/14 10:37 */ public class Person { private String name = "劉瑜澄";//設(shè)置初始值 private int age = 22; public Person() {//無(wú)參構(gòu)造 } public Person(String name, int age) {//有參構(gòu)造 this.name = name; this.age = age; } public void sayHello() {//無(wú)參方法 System.out.println(name + ":使用sayHello方法"); } public void sayGoodBye() {//無(wú)參方法 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è)用于測(cè)試反射的實(shí)體類創(chuàng)建成功后,先學(xué)習(xí)反射中是如何獲取類對(duì)象的。
反射的第一步就是要獲取操作類的類對(duì)象,即一個(gè)Class的實(shí)例,JVM中每個(gè)被加載的類有且只有一個(gè)類對(duì)象與之對(duì)應(yīng),獲取到這個(gè)類對(duì)象后我們就可以通過這個(gè)類對(duì)象來(lái)了解該類的一切信息(類名、有哪些方法、屬性等等) 以便在程序運(yùn)行期間通過反射機(jī)制進(jìn)行相關(guān)操作
這里介紹三種獲取類對(duì)象的方式:
(包名.)類名.class
Class personClass = reflect_text.Person.class; Class intClass = int.class;
這種方式最直接,但是由于是靠硬編碼形式寫死(編譯期間已經(jīng)確定),因此不夠靈活。但是需要注意,基本類型(int\double等)只能通過這種方式獲取類對(duì)象
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è)簡(jiǎn)單的方法:
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"); }
Class類中提供了一個(gè)方法newInstance()來(lái)實(shí)例化,該方法要求此類必須具有無(wú)參構(gòu)造器,它是通過無(wú)參構(gòu)造器實(shí)例化對(duì)象的。
Person person = new Person(); //1獲取要實(shí)例化的類的類對(duì)象 Scanner scanner = new Scanner(System.in); System.out.println("請(qǐng)輸入類名:"); Class cls = Class.forName(scanner.nextLine()); /* 通過Class提供的方法newInstance()來(lái)實(shí)例化 該方法要求此類必須具有無(wú)參構(gòu)造器,它是通過無(wú)參構(gòu)造器實(shí)例化對(duì)象的 */ Object obj = cls.newInstance(); System.out.println("obj = " + obj);
getConstructor() //獲取無(wú)參構(gòu)造器,可以利用無(wú)參構(gòu)造器實(shí)例化對(duì)象,但這個(gè)方法對(duì)于使用無(wú)參構(gòu)造器實(shí)例化對(duì)象可有可無(wú) getConstructor(類對(duì)象) //通過類對(duì)象獲取特定的構(gòu)造器,該參數(shù)列表是根據(jù)特定構(gòu)造器的參數(shù)列表類型來(lái)決定的,如 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; }
舉例
//加載類對(duì)象 Class cls = Class.forName("reflect.Person"); //通過類對(duì)象獲取特定的構(gòu)造器 Constructor c = cls.getConstructor(String.class, int.class); Object o = c.newInstance("流年", 21);//實(shí)例化 System.out.println(o);
結(jié)果可知初始值已經(jīng)被修改
getMethod(String MethodName) 獲取類對(duì)象的MethodName方法,返回值類型為Method invoke(Object object) 執(zhí)行object對(duì)象的某方法
舉例
//一般調(diào)用方法的做法------------------- Person p = new Person();//實(shí)例化對(duì)象 p.sayHello();//調(diào)用該對(duì)象方法 //反射機(jī)制調(diào)用方法----------------------- //1、實(shí)例化對(duì)象 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á)到一樣的效果
getMethod(String MethodName, 類對(duì)象) 獲取類對(duì)象的MethodName有參方法,并傳入對(duì)應(yīng)參數(shù)類型的類對(duì)象,返回值類型為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é)果可以看到,效果都是一樣的
注意:反射訪問私有的方法,但是會(huì)破壞類的封裝性
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);
加載資源時(shí)常用相對(duì)路徑,之前學(xué)習(xí)的相對(duì)路徑./由于運(yùn)行環(huán)境不同,位置并非固定,因此實(shí)際開發(fā)中使用較少。
接下來(lái)介紹,在開發(fā)中常用的類加載路徑
常用的路徑通常為類的加載路徑,有兩個(gè):
1:類對(duì)象.getResource()
與當(dāng)前類所處同一目錄
2:類加載器.getResource()
類加載路徑,類的package定義中根包位置。
例如:有一個(gè)類: package reflect_text; public class WebServer{ …… } 在WebServer類中,當(dāng)我們使用上述兩種方式獲取路徑時(shí)他們的對(duì)應(yīng)位置為: WebServer.class.getResource() 當(dāng)前WebServer所在的目錄(編譯后的class文件所在目錄) WebServer.class.getClassLoader().getResource() 則是在WebServer的包的最上級(jí),即com包的上一級(jí)
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 }
感謝各位的閱讀,以上就是“Java中的反射機(jī)制的基本運(yùn)用”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)Java中的反射機(jī)制的基本運(yùn)用這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。