Java中的反射機制基本運用
看完反射可以了解一下注解
注解annotation:http://www.jfrwli.cn/article/211485.html
1、什么是反射(reflect)
反射是java的動態(tài)機制,它允許將對象的實例化,方案的調(diào)用,屬性的操作等從編碼期確定轉(zhuǎn)移到程序運行期確定。
反射能大大提高代碼的靈活度。但同時也帶來了更多的系統(tǒng)開銷和較慢的運行效率,因此程序不能過度依賴反射。
2、反射機制提供的功能
- 在運行時判斷任意一個對象所屬的類
- 在運行時構造任意一個類的對象(實例化)
- 在運行時判斷任意一個類所具有的成員變量和方法
- 在運行時調(diào)用任意一個對象的方法——動態(tài)代理
3、反射->獲取類對象
在開始之前創(chuàng)建一個實體類,用于測試反射機制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
package reflect_text; /** * 用于測試反射機制 * * @author Akio * @Create 2021/8/14 10:37 */ public class Person { private String name = "劉瑜澄" ; //設置初始值 private int age = 22 ; public Person() { //無參構造 } public Person(String name, int age) { //有參構造 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 + ":這是一個私有方法" ); } @Override public String toString() { return "Person{" + "name='" + name + '\ '' + ", age=" + age + '}' ; } } |
以上這個用于測試反射的實體類創(chuàng)建成功后,先學習反射中是如何獲取類對象的。
反射的第一步就是要獲取操作類的類對象,即一個Class的實例,JVM中每個被加載的類有且只有一個類對象與之對應,獲取到這個類對象后我們就可以通過這個類對象來了解該類的一切信息(類名、有哪些方法、屬性等等) 以便在程序運行期間通過反射機制進行相關操作
這里介紹三種獲取類對象的方式:
-
(包名.)類名.class
1
2
|
Class personClass = reflect_text.Person. class ; Class intClass = int . class ; |
這種方式最直接,但是由于是靠硬編碼形式寫死(編譯期間已經(jīng)確定),因此不夠靈活。但是需要注意,基本類型(int\double等)只能通過這種方式獲取類對象
-
Class.forName(String className)
1
2
|
Class personClass = Class.forName( "reflect_text.Person" ); Class stringClass = Class.forName( "java.lang.String" ); |
這種方式較為常用,遵循運行期綁定。
-
類加載器ClassLoader
1
2
|
Class stringClass = ClassLoader.getSystemClassLoader().loadClass( "java.lang.String" ); Class personClass = ClassLoader.getSystemClassLoader().loadClass( "reflect_text.Person" ); |
在這一節(jié)中介紹幾個簡單的方法:
1
2
3
4
5
6
|
getName() 獲取類的完全限定名:包名.類名 getSimpleName() 僅僅獲取類名 getMethods() 返回一個Method數(shù)組,獲取 class 所表示的類的所有公開方法(包含從超類中繼承的方法) |
例子:
1
2
3
4
5
6
7
8
9
10
|
Scanner scanner = new Scanner(System.in); Class cls = Class.forName(scanner.nextLine()); //運行期綁定 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、反射->利用無參構造實例化對象
Class類中提供了一個方法newInstance()來實例化,該方法要求此類必須具有無參構造器,它是通過無參構造器實例化對象的。
1
2
3
4
5
6
7
8
9
10
11
|
Person person = new Person(); //1獲取要實例化的類的類對象 Scanner scanner = new Scanner(System.in); System.out.println( "請輸入類名:" ); Class cls = Class.forName(scanner.nextLine()); /* 通過Class提供的方法newInstance()來實例化 該方法要求此類必須具有無參構造器,它是通過無參構造器實例化對象的 */ Object obj = cls.newInstance(); System.out.println( "obj = " + obj); |
5、反射->利用有參構造實例化對象
1
2
3
4
5
6
7
8
9
10
|
getConstructor() //獲取無參構造器,可以利用無參構造器實例化對象,但這個方法對于使用無參構造器實例化對象可有可無 getConstructor(類對象) //通過類對象獲取特定的構造器,該參數(shù)列表是根據(jù)特定構造器的參數(shù)列表類型來決定的,如 getConstructor(String. class , int . class ) 即為調(diào)用Person類中兩個參數(shù)的有參構造器 public Person(String name, int age) { //有參構造 this .name = name; this .age = age; } |
舉例
1
2
3
4
5
6
|
//加載類對象 Class cls = Class.forName( "reflect.Person" ); //通過類對象獲取特定的構造器 Constructor c = cls.getConstructor(String. class , int . class ); Object o = c.newInstance( "流年" , 21 ); //實例化 System.out.println(o); |
結果可知初始值已經(jīng)被修改
6、反射->調(diào)用無參方法
1
2
3
4
|
getMethod(String MethodName) 獲取類對象的MethodName方法,返回值類型為Method invoke(Object object) 執(zhí)行object對象的某方法 |
舉例
1
2
3
4
5
6
7
8
9
10
11
12
|
//一般調(diào)用方法的做法------------------- Person p = new Person(); //實例化對象 p.sayHello(); //調(diào)用該對象方法 //反射機制調(diào)用方法----------------------- //1、實例化對象 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() |
可見兩種操作均能達到一樣的效果
7、反射->調(diào)用有參方法
1
2
|
getMethod(String MethodName, 類對象) 獲取類對象的MethodName有參方法,并傳入對應參數(shù)類型的類對象,返回值類型為Method |
舉例
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//一般調(diào)用有參方法------------------------ Person p = new Person(); p.say( "七夕快樂~" ); p.say( "七夕快樂~" , 3 ); //反射機制調(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 ); |
通過結果可以看到,效果都是一樣的
8、反射->訪問私有方法
注意:反射訪問私有的方法,但是會破壞類的封裝性
1
2
3
4
|
getDeclaredMethod(String MethodName) 可以僅獲取此類定義的所有方法,包含私有方法 setAccessible(boolean flag) 開啟私有方法的訪問權限 |
舉例
1
2
3
4
5
6
7
|
//正常情況下,在本類中不可以訪問外部的私有方法 //但在反射機制中可行 Class cls = Class.forName( "reflect_text.Person" ); Object o = cls.newInstance(); Method method = cls.getDeclaredMethod( "privateMethod" ); method.setAccessible( true ); //打開訪問權限 method.invoke(o); |
9、反射->類加載路徑
加載資源時常用相對路徑,之前學習的相對路徑./由于運行環(huán)境不同,位置并非固定,因此實際開發(fā)中使用較少。
接下來介紹,在開發(fā)中常用的類加載路徑
常用的路徑通常為類的加載路徑,有兩個:
1:類對象.getResource()
與當前類所處同一目錄
2:類加載器.getResource()
類加載路徑,類的package定義中根包位置。
1
2
3
4
5
6
7
8
9
10
|
例如:有一個類: package reflect_text; public class WebServer{ …… } 在WebServer類中,當我們使用上述兩種方式獲取路徑時他們的對應位置為: WebServer. class .getResource() 當前WebServer所在的目錄(編譯后的 class 文件所在目錄) WebServer. class .getClassLoader().getResource() 則是在WebServer的包的最上級,即com包的上一級 |
1
2
3
4
5
6
7
8
9
|
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 } |
總結
本片文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注服務器之家的更多內(nèi)容!
原文鏈接:https://blog.csdn.net/Grantr/article/details/119966805