反射是什麼
反射: 將類的各個組成部分封裝成其他對象
反射是框架實際的靈魂
框架: 半成品軟件,可以在狂角點基礎上進行軟件開發
反射帶來的好處
- 可以在程序運行過程中,操作這些對象
- 可以解耦
Java程序執行過程
拿一個People類說明
public class People {
//成員變量
private int age;
private String name;
//構造方法
public People(){}
//成員方法
public void say(){System.out.println(name+"say...");}
/**圖片空間有限 下面的就不在圖片標明瞭**/
public People(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
@Override
public String toString() {
return "People{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
下面用一張圖來說明
- 源代碼階段:此時文件還處於硬盤中,並沒有加載
- class類階段:使用類加載器吧.class文件加載成一個class對象
- 運行時階段:在創建對象的時候,將class裏的內容封裝成一個對象
獲取class對象
class對象的獲取方式有以下三種
- 使用
Class.forName("全類名");
- 類名.class
- 對象.getClass();
下面用代碼來演示
public static void main(String[] args) throws Exception {
// 1. 使用`Class.forName("全類名");`
Class cls1 = Class.forName("test.People");
// 2. 類名.class
Class cls2 = People.class;
// 3. 對象.getClass();
People people = new People();
Class cls3 = people.getClass();
//輸出3個對象
System.out.println(cls1);
System.out.println(cls2);
System.out.println(cls3);
//對比三個對象
System.out.println(cls3 == cls1);
System.out.println(cls2 == cls1);
System.out.println(cls3 == cls2);
}
輸出結果
class test.People
class test.People
class test.People
true
true
true
由此可見 他們三種的獲取的class對象 都是同一個對象
使用 Class對象
獲取功能
下面說幾種常見的功能
- 獲取成員變量們
-
Field getField(String name)
返回一個public的指定名稱的 Field對象。 -
Field[] getFields()
返回所有public的 Field對象數組。 -
Field getDeclaredField(String name)
返回一個指定名稱的 Field對象。 -
Field[] getDeclaredFields()
返回所有 Field對象數組。
-
- 獲取構造方法們
-
Constructor<T> getConstructor(Class<?>... parameterTypes)
返回一個指定public的 Constructor對象。 -
Constructor<?>[] getConstructors()
返回public的Constructor對象數組。 -
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
返回一個指定的 Constructor對象。 -
Constructor<?>[] getDeclaredConstructors()
返回所有Constructor對象。
-
- 獲取成員方法們
Method getMethod(String name, Class<?>... parameterTypes)
返回一個指定的public的 Method 對象。Method[] getMethods()
返回所有public的 Method對象。Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一個指定的 Method 對象。Method[] getDeclaredMethods()
返回所有 Method對象。
- 獲取名稱
String getName()
- 獲取註解
-
<A extends Annotation> A getAnnotation(類<A> annotationClass)
返回指定類型的註解,如果沒有返回null。 -
Annotation[] getAnnotations()
返回此元素上 存在的註釋。
-
成員變量的修改和獲取
- 獲取值
get(Object obj)
- 設置值
set(Object obj,Object value)
- 暴力反射
setAccessible(true)
//獲取public 修飾的
Field[] names = cls1.getFields();
for (Field name : names) {
System.out.println(name);
}
我們先來獲取所有的變量,但是輸出卻一個也沒有???
原來所有的變量都是private的
所以我們用第二種
//獲取所有的變量
Field[] names = cls1.getDeclaredFields();
for (Field name : names) {
System.out.println(name);
}
下面輸出結果,這個時候就有輸出了
private int test.People.age
private java.lang.String test.People.name
我們也可以對變量進行修改
People p = new People();
p.setName("李四");
//獲取name變量
Field field = cls1.getDeclaredField("name");
System.out.println(field.get(p));
雖然邏輯上看上去沒有一點問題,但是程序一執行立即報錯
報錯的原因就是訪問權限修飾符的安全檢查
因爲private是不允許被外界訪問的
所以 這裏需要暴力反射
在原來的代碼上加上field.setAccessible(true);
People p = new People();
p.setName("李四");
//獲取name變量
Field field = cls1.getDeclaredField("name");
//允許暴力反射
field.setAccessible(true);
System.out.println(field.get(p));//李四
field.set(p,"張三");
System.out.println(field.get(p));//張三
這樣就可以對private變量進行修改和獲取了
構造方法是使用和創建對象
- 創建對象方法
newInstance(Object...args)
- 暴力反射
setAccessible(true)
//獲取構造器對象
Constructor wu_can = cls1.getConstructor();//無參構造
Constructor you_can = cls1.getConstructor(int.class, String.class);//有參數
//創建對象
Object p1 = wu_can.newInstance();
System.out.println(p1);
//修改信息
People zhang_san = (People) p1;//強制轉換
zhang_san.setAge(25);
zhang_san.setName("張三");
System.out.println(p1);//和zhang_san是同一個對象
//使用有參數構造器創建對象
Object p2 = you_can.newInstance(20,"李四");
System.out.println(p2);
輸出結果
People{age=0, name='null'}
People{age=25, name='張三'}
People{age=20, name='李四'}
成員方法的調用以及返回值的獲取
- 執行方法
invoke(Object obj,Object...args)
返回返回值 - 暴力反射
setAccessible(true)
People p = new People(20,"張三");//執行對象
Object obj;//返回值
//調用say()
Method say = cls1.getMethod("say");
obj = say.invoke(p);//say()沒有返回值
System.out.println("say-obj:"+obj);
//調用setName()
Method setName = cls1.getMethod("setName", String.class);
obj = setName.invoke(p,"李四");//setName沒有返回值
System.out.println("setName-obj:"+obj);
//調用getName()
Method getName = cls1.getMethod("getName");
obj = getName.invoke(p);//這裏有返回值
System.out.println("getName-obj:"+obj);
輸出結果如下
張三say...
say-obj:null
setName-obj:null
getName-obj:李四