[Java核心技術]-反射技術

反射是什麼

反射: 將類的各個組成部分封裝成其他對象

反射是框架實際的靈魂

框架: 半成品軟件,可以在狂角點基礎上進行軟件開發

反射帶來的好處

  • 可以在程序運行過程中,操作這些對象
  • 可以解耦

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:李四
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章