反射是Java 語言的特征之一,它允許運行中的Java程序獲取自身的信息,并且可以操作類或?qū)ο蟮膬?nèi)部屬性。通過反射,可以在運行時獲得程序中每一個類型的成員和成員的信息。程序中一般的對象的類型都是在編譯期就確定下來的,而Java反射機制可以動態(tài)地創(chuàng)建對象并調(diào)用其屬性,這樣的對象的類型在編譯期是未知的。
反射的核心是JVM在運行時才動態(tài)加載類或調(diào)用方法/訪問屬性,它不需要事先知道運行對象是誰。
Java反射框架主要提供以下功能:
- 在運行時判斷任意一個對象所屬的類;
- 在運行時構(gòu)造任意一個類的對象;
- 在運行時判斷任意一個類所具有的成員變量和方法;
- 在運行時調(diào)用任意一個對象的方法
當我們在使用IDE(如Eclipse,IDEA)時,當我們輸入一個對象或類并想調(diào)用它的屬性或方法時,一按點號,編譯器就會自動列出它的屬性或方法,這里就會用到反射。
反射最重要的用途就是開發(fā)各種通用框架。
操作反射常用的類:Constructor、Field、Method、Array位于java.lang.reflect包中。
通過反射獲取類的信息分為兩步:
-
獲取Class對象
- 調(diào)用對象的getClass()方法
- 調(diào)用類的class屬性
- 調(diào)用Class類的forName()方法
-
通過Class對象獲取信息
- 訪問Class對應(yīng)的類的構(gòu)造方法
- 訪問Class對應(yīng)的類的方法
- 訪問Class對應(yīng)的類的屬性
訪問Class對應(yīng)的類的構(gòu)造方法
| 訪問Class對應(yīng)的類的構(gòu)造方法 | 說明 |
|---|---|
| Constructor getConstructor(Class[ ] params) | 返回此Class對象所包含的類的指定的public構(gòu)造方法 |
| Constructor[ ] getConstructors( ) | 返回此Class對象所包含的類的所有的public構(gòu)造方法 |
| Constructor getDeclaredConstructor(Class[ ] params) | 返回此Class對象所包含的類的聲明的指定的構(gòu)造方法 |
| Constructor[ ] getDeclaredConstructors( ) | 返回此Class對象所包含的類的聲明的所有構(gòu)造方法 |
訪問Class對應(yīng)的類的方法
| 訪問Class對應(yīng)的類的方法 | 說明 |
|---|---|
| Method getMethod(String name, Class[ ] params) | 返回此Class對象所包含的類的指定的public方法 |
| Method[ ] getMethods( ) | 返回此Class對象所包含的類的所有的public方法 |
| Method getDeclaredMethod(String name, Class[ ] params) | 返回此Class對象所包含的類的聲明的指定的方法 |
| Method[ ] getDeclaredMethods( ) | 返回此Class對象所包含的類的聲明的所有方法 |
訪問Class對應(yīng)的類的屬性
| 訪問Class對應(yīng)的類的屬性 | 說明 |
|---|---|
| Field getField(String name) | 返回此Class對象所包含的類的指定的public屬性 |
| Field[ ] getFields( ) | 返回此Class對象所包含的類的所有的public屬性 |
| Field getDeclaredField(String name) | 返回此Class對象所包含的類的聲明的指定的屬性 |
| Field[ ] getDeclaredFields( ) | 返回此Class對象所包含的類的聲明的所有屬性 |
Array類操作數(shù)組
Array類里定義了大量靜態(tài)方法,通過類名直接調(diào)用。
這里的Array和集合框架里的Arrays不一樣,他們的相同點都是定義了大量靜態(tài)方法,都是數(shù)組的操作,Array位于java.lang.relect包,是動態(tài)創(chuàng)建并操作數(shù)組;Arrays位于java.util包,是一個工具類,其中包含了一些方法可直接實現(xiàn)數(shù)組的排序、搜索等。
下面結(jié)合代碼做下說明:
public class Demo {
//調(diào)用class對象會拋出大量異常,這里為簡化代碼,直接拋給jvm
public static void main(String[] args) throws Exception {
Student stu = new Student("張三",23);
//獲取Class對象
//方法一:forName()方法,必須要完整的包名加類名
Class<?> stuClass = Class.forName("reflect.Student");
//方法二:類的class屬性
Class<?> cla1 = Student.class;
//方法三:getClass()方法
Class<?> cla2 = stu.getClass();
System.out.println(stuClass.getName());
//獲取聲明的所有構(gòu)造方法
Constructor<?>[] constructor = stuClass.getConstructors();
for (int i = 0; i < constructor.length; i++) {
System.out.println(constructor[i].toString());
}
//獲取指定的一個有參構(gòu)造方法
Constructor<?> con1 = stuClass.getDeclaredConstructor(String.class,int.class);
Object obj = con1.newInstance("tom",20); //使用Class對象的newInstance()方法創(chuàng)建對象
((Student)obj).shwoInfo();
//獲取聲明的所有屬性
Field[] fields = stuClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
System.out.println(fields[i].toString());
}
//獲取public name屬性,并改變其值
Field fieldname = stuClass.getDeclaredField("name");
fieldname.set(stu, "王小二");//set方法給屬性賦值
String nameStr = (String) fieldname.get(stu); //get方法取出屬性的值
System.out.println(nameStr);
//獲取private age屬性,并改變其值
Field fieldAge = stuClass.getDeclaredField("age");
fieldAge.setAccessible(true); //改變屬性訪問權(quán)限
fieldAge.set(stu, 58);
int ageInt = fieldAge.getInt(stu);
System.out.println(ageInt);
//獲得聲明的所有方法
Method[] methods = stuClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
System.out.println(methods[i].toString());//以字符串形式打印出方法名
}
//獲得聲明的指定方法,傳值并調(diào)用
Method m1 = stuClass.getDeclaredMethod("sayHelloTo", String.class);
m1.invoke(null, "jerry");//這里的null是因為調(diào)用的方法是靜態(tài)方法,不用傳對象
//獲得其中一個方法,直接調(diào)用
Method m2 = stuClass.getDeclaredMethod("shwoInfo");
m2.invoke(stu);//用invoke()調(diào)用方法時需要傳一個對象
//Array操作數(shù)組
Object arr = Array.newInstance(int.class, 3);//創(chuàng)建元素為3的int數(shù)組
for (int i = 0; i < Array.getLength(arr); i++) {
Array.set(arr, i, 2*i); //循環(huán)給元素賦值
}
for (int i = 0; i < Array.getLength(arr); i++) {
System.out.println(Array.get(arr, i));//循環(huán)取值
}
Array.set(array, 0, 99);//指定元素賦值
System.out.println(Array.get(array, 0));//指定元素取值
}
}