一篇文章帶你深入理解java反射機制

反射

Reflection(反射)是 Java 程序開發語言的特徵之一,它允許運行中的 Java 程序對自身進行檢查,或者說“自審”,也有稱作“自省”。反射非常強大,它甚至能直接操作程序的私有屬性。我們前面學習都有一個概念,private的只能類內部訪問,外部是不行的,但這個規定被反射赤裸裸的打破了。

反射就像一面鏡子,它可以在運行時獲取一個類的所有信息,可以獲取到任何定義的信息(包括成員變量,成員方法,構造器等),並且可以操縱類的字段、方法、構造器等部分。

爲什麼需要反射:

好好的我們new User(); 不是很好,爲什麼要去通過反射創建對象呢?那我要問你個問題了,你爲什麼要去餐館喫飯呢?例如:我們要喫個牛排大餐,如果我們自己創建,就什麼都得管理。

好處是,每一步做什麼我都很清晰,壞處是什麼都得自己實現,那不是累死了。牛接生你管,喫什麼你管,屠宰你管,運輸你管,冷藏你管,烹飪你管,上桌你管。就拿做菜來說,你能有特級廚師做的好?

那怎麼辦呢?有句話說的好,專業的事情交給專業的人做,飼養交給農場主,屠宰交給劊子手,烹飪交給特級廚師。那我們幹嘛呢?

我們翹起二郎腿直接拿過來喫就好了。再者,飯店把東西做好,不能扔到地上,我們去撿着喫吧,那不是都成原始人了。那怎麼辦呢?很簡單,把做好的東西放在一個容器中吧,如把牛排放在盤子裏。

在開發的世界裏,spring就是專業的組織,它來幫我們創建對象,管理對象。我們不在new對象,而直接從spring提供的容器中beans獲取即可。Beans底層其實就是一個Map<String,Object>,最終通過getBean(“user”)來獲取。而這其中最核心的實現就是利用反射技術。

總結一句,類不是你創建的,是你同事或者直接是第三方公司,此時你要或得這個類的底層功能調用,就需要反射技術實現。有點抽象,彆着急,我們做個案例,你就立馬清晰。

反射Class類對象

  • Class.forName(“類的全路徑”);
  • 類名.class
  • 對象.getClass();

常用方法

  • 獲得包名、類名
  • getPackage().getName()//包名
  • getSimpleName()//類名
  • getName()//完整類名

!!成員變量定義信息

  • getFields()//獲得所有公開的成員變量,包括繼承的變量
  • getDeclaredFields()//獲得本類定義的成員變量,包括私有,不包括繼承的變量
  • getField(變量名)
  • getDeclaredField(變量名)

!!構造方法定義信息

  • getConstructor(參數類型列表)//獲得公開的構造方法
  • getConstructors()//獲得所有公開的構造方法
  • getDeclaredConstructors()//獲得所有構造方法,包括私有
  • getDeclaredConstructor(int.class, String.class)

方法定義信息

  • getMethods()//獲得所有可見的方法,包括繼承的方法
  • getMethod(方法名,參數類型列表)
  • getDeclaredMethods()//獲得本類定義的方法,包括私有,不包括繼承的方法
  • getDeclaredMethod(方法名, int.class, String.class)

反射新建實例

  • newInstance();//執行無參構造
  • newInstance(6, “abc”);//執行有參構造
  • getConstructor(int.class, String.class); //執行含參構造,獲取構造方法

反射調用成員變量

  • getDeclaredField(變量名); //獲取變量
  • setAccessible(true); //使私有成員允許訪問
  • set(實例, 值); //爲指定實例的變量賦值,靜態變量,第一參數給 null
  • get(實例); //訪問指定實例的變量的值,靜態變量,第一參數給 null

反射調用成員方法

  • 獲取方法
  • Method m = c.getDeclaredMethod(方法名, 參數類型列表);
  • m.setAccessible(true) ;//使私有方法允許被調用
  • m.invoke(實例, 參數數據) ;//讓指定的實例來執行該方法

反射的應用

創建類

class Student{
    String name="jack";
    int age=20;    
    public Student() {
       System.out.println("無參構造");
    }
    public Student(String name) {
       this.name=name;
       System.out.println("含參構造"+name);
    }    
    public void show(int a) {
       System.out.println("show()..."+a);
    }    
}

獲取類對象

private static void method() throws Exception {
   Class clazz = Student.class;
   Class<?> clazz2 = Class.forName("seday15.Student");
   Class clazz3 = new Student().getClass();       
   System.out.println(clazz.getName());
   System.out.println(clazz2.getName());
   System.out.println(clazz3.getName());
}

獲取構造方法

private static void method3(Class clazz) {
       Constructor[] cs = clazz.getDeclaredConstructors();
       for (Constructor c : cs) {
           String name = clazz.getSimpleName();
           System.out.println(name);           
           Class[] cs2 = c.getParameterTypes();//參數
           System.out.println(Arrays.toString(cs2));           
       }
 }

獲取成員方法

private static void method4(Class clazz) {
     Method[] ms = clazz.getMethods();
       for (Method m : ms) {
           String name = m.getName();
           System.out.println(name);           
           Class<?>[] cs = m.getParameterTypes();
           System.out.println(Arrays.toString(cs));
       }
}

獲取成員變量

  private static void method2(Class clazz) {
       Field[] fs = clazz.getFields();//獲取public的屬性
       for (Field f : fs) {
           String name = f.getName();
           String tname = f.getType().getSimpleName();
           System.out.println(name);
           System.out.println(tname);
       }
}

我們再來說說暴力反射,什麼是暴力反射呢?Java中有許多的方法和對象爲了安全考慮,都被封裝在類中。通常這些私有的方法和對象都只能在該類的內部進行調用,對於外部的類來說,都是隱藏、不可見的。爲了能夠在外部類中獲取和操作這些私有的對象和方法,就可以使用暴力反射的方式來實現。簡單來講就是指可以將程序中的私有的屬性或者方法通過反射技術,暴力的獲取到資源。

創建Person類

class Person{    
    private String name="jack";
    private int age = 30;    
    private void show(int[] a) {
       System.out.println("show()..."+Arrays.toString(a));
    }
    private void test() {
       System.out.println("test()...");
    }
}

看以上這個例子,成員變量和成員方法都是私有的,那麼我們將如何獲取它的值呢?我們來測試一下

package seday16new;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectPerson {
    public static void main(String[] args) throws Exception {
       Class<?> clazz = Class.forName("seday16new.Person");
//     method(clazz);//隱私屬性
       method2(clazz);//執行方法
    }
    
    private static void method2(Class<?> clazz) throws Exception {
       Method m = clazz.getDeclaredMethod("show", int[].class);
       Object obj = clazz.newInstance();
       m.setAccessible(true);//方法隱私可見
       m.invoke(obj, new int[]{1,2,3});//執行
    } 
    
    private static void method(Class clazz) throws Exception {
       Field f = clazz.getDeclaredField("name");
       System.out.println(f.getType().getName());
       f.setAccessible(true);//屬性隱私可見
       Object obj = clazz.newInstance();
//     f.set(obj, "rose");//設置值
       System.out.println(f.get(obj));//獲取值   
              
       //---所有屬性
       Field[] fs = clazz.getDeclaredFields();
       for (Field ff : fs) {
           System.out.println(ff);
           ff.setAccessible(true);//暴力反射
           System.out.println(ff.get(obj));
       }       
    }    
}

結果:

  • 獲取私有屬性值並修改
  • 獲取私有方法並執行

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章