四大神器之反射

Java反射機制,是一個基礎的內容章節,在對於以後的框架學習中起到了相當重要的做用,如今比較流行的是springjava

框架 ,其中的IOC(自動注入)以及AOP(動態代理),在AOC中代理模式又分爲動態代理和byteCodespring

instrument(插樁)或者是CGLIB 。app

在學習Java反射機制前,首先問一個問題:在Java運行時,對於任意一個類,可否知道這個類有那些屬性和方法?對框架

 

於任意一個對象,可否調用它任意一個方法?學習

 

答案是確定的。能夠!this

 

在這裏要去區別一個事情:若是說在本身寫的類中去改一個數據類型或者說屬性,那只是在編譯時,並非在運行spa

 

時。命令行

 

反射機制的幾大功能:代理

 

  • 在運行時,判斷任意一個對象所屬類。
  • 在運行時,構造任意一個對象。
  • 在運行時,判斷任意一個類所具備的成員變量和方法
  • 在運行時,調用任意一個對象的方法。

 

通常而言:程序運行時,容許改變程序結構和變量類型成爲動態語言。因而可知Java並非動態語言,可是Java有一code

 

個動態相關的機制Reflection,能夠運行時加載、探知、使用編譯期間徹底未知的classes(可是methods定義不知

 

道)。因此Reflection是Java視爲動態語言的關鍵性質,容許在程序運行時經過Reflection APIs 取得任何一個已知名

 

稱的class的內部信息。(包括父類,接口,變量,方法等)。

 

接下來咱們用代碼來舉一個例子。

 

public class DumpMethods { //從命令行接受一個字符串(該字符串是某個類的全名) //打印該類的全部方法

    public static void main(String[] args) throws ClassNotFoundException { //class類是全部反射的入口
        Class<?> classType = Class.forName(args[0]);//編譯時不知道args是什麼?
 Method[] methods = classType.getDeclaredMethods(); for (Method method : methods) { System.out.println(method); } } }

 

 

 

在這裏,咱們能夠看到,Java虛擬機並不知道你所要傳入的參數是什麼,這個時候咱們類的全類型名

 

稱 Java.lang.String輸入進去,咱們能夠看到以下圖片

 

結果.jpg

 

其中,標紅的那一行能夠看到,直接將私有的方法也可顯示出來。這一個是很是有用的。那麼這些代碼就能夠很明顯

 

的讓咱們知道,在Java運行時,就能夠判斷任意一個對象所屬類。

 

接下來,咱們來看一下反射的相關代碼:

 

public class InvokeTester { public int add(int param1, int param2) { return param1 + param2; } public String echo(String msg) { return msg + "hello"; } public static void main(String[] args) throws Exception { Class<?> classType = InvokeTester.class; //獲取類對象
 Object invokeTester = classType.newInstance();//建立此 Class 對象所表示的類的一個新實例。 //調用前提是 必須有一個不帶參數的構造器 //以上兩行代碼就至關於new invokeTester
 Method addmethod = classType.getMethod("add", int.class, int.class);//肯定這個方法須要輸入 方法名 參數
 Object result = addmethod.invoke(invokeTester, new Object[]{100, 200}); //以上兩行至關於i.add(100,200)
 System.out.println((Integer) result); Method echoMethod = classType.getMethod("echo", new Class[]{String.class}); Object result2 = echoMethod.invoke(invokeTester, "hello world"); System.out.println((String) result2); } }

 

 

在這裏,着重說獲取類對象時,建立的class對象新的實例時,必須有一個不帶參數的構造器,不然會報錯,那麼怎

 

沒有應該怎麼辦呢?下面會講到。確認一個方法,咱們經過重載機制就能夠知道,須要經過這個方法的名字和他的參

 

數來確認。上一個咱們經過classType.getDeclareMethods()來獲取了全部方法,而如今咱們能夠經過

 

classType.getMethods()方法來得到這個咱們須要已知方法的名字,在這裏參數類型是int.class,String.class.在之

 

後,咱們經過revoke方法,來得到咱們調用方法的結果,invoke方法中的兩個參數,第一個參數是咱們須要調用的對

 

象,第二個參數就是調用方法的參數,這個參數應該與getmethod方法的參數所寫的類型一致,下面咱們來看一下結

 

果:

Snipaste_2020-01-10_11-55-11.jpg

 

咱們經過這個例子,就能夠發現,經過反射機制咱們徹底能夠調用一個方法。

 

接下來,整一個複雜點的!

 

public class ReflectTester { public Object copy(Object object) throws Exception { Class<?> classType = object.getClass(); System.out.println(classType.getName()); Object objectCopy = classType.getConstructor(new Class[]{}) .newInstance(new Object[]{}); //至關因而 object object2 = classType.newInstance(); //得到對象的全部屬性
        Field[] fields = classType.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; String fieldName = field.getName(); //得到屬性的首字母並轉換爲大寫
            String firstLetter = fieldName.substring(0, 1).toUpperCase(); //得到和屬性對應的getxxx()方法
            String getMethodName = "get" + firstLetter + fieldName.substring(1); //得到個屬性對應的setxxx()方法
            String setMethodName = "set" + firstLetter + fieldName.substring(1); //得到get方法
            Method getMethod = classType.getMethod(getMethodName, new Class[]{}); //得到set方法
            Method setMethod = classType.getMethod(setMethodName, new Class[]{field.getType()}); Object value = getMethod.invoke(object, new Object[]{}); System.out.println(fieldName + ":" + value); setMethod.invoke(objectCopy, new Object[]{value}); } return objectCopy; } public static void main(String[] args) throws Exception { Customer customer = new Customer(); customer.setId(new Long(1)); customer.setName("zhangsan"); customer.setAge(20); Customer customerCopy = (Customer) new ReflectTester().copy(customer); System.out.println(customerCopy.getId() + "," + customerCopy.getName() + "," + customerCopy.getAge()); } } class Customer { private long id; private String name; private int age; public Customer() { } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }

 

 

以上代碼創造了一個Customer類,並經過反射進行了一次copy,調用getter,setter方法,成功。此處必定要在

 

Customer類中寫入構造器,不然容易形成權限不經過致使沒有辦法讀取。咱們能夠看到  Object object copy =

 

classType.getConstructor(new Class[]{}) .newInstance(new Object[]{});這一行代碼就至關因而object object2 =

 

classType.newInstance();若是沒有無參構造器時,則可運用這個方法

Snipaste_2020-01-10_11-59-09.jpg

相關文章
相關標籤/搜索