java反射機制的簡單介紹

来源:https://www.cnblogs.com/xumBlog/archive/2018/04/19/8882489.html
-Advertisement-
Play Games

參考博客: https://blog.csdn.net/mlc1218559742/article/details/52754310 先給出反射機制中常用的幾個方法: 現在開始對java反射機製做簡單的介紹 JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一 ...


參考博客: https://blog.csdn.net/mlc1218559742/article/details/52754310

先給出反射機制中常用的幾個方法:

Class.forName ("類名")
Class.forName ("類名").newInstance
Class.getMethod ("調用的方法名",class[]{參數類列表})
instance.getClass
Method.invoke ("對象名","參數封裝成的對象")
這裡簡單的給出java反射機制的測試小例子, 大家看不懂的話, 可以跳過這裡, 看下麵對java反射機制的介紹, 看完之後, 再回來看這個小例子, 應該很簡單了哦.
Class InvokeTest{
private static String algorithm = "Algorithm"; Object invokeMethod(object instance,String fun, Class[] paras, Object[] paraValue){   Object result = null;   Method method;   try{   method = instance.getClass.getMethod(fun, paras);   result = method.invoke(instance, paraValue);   }catch(Exception e) {   e.printStackTrace();   result = null;   }    }    public static void main(){   int x = 10, y = 20;   invokeMethod(Class.forName(algorithm), newInstance, "add", Class[]{Class.int, Class.int}, Object[]{new Integer(x), new Integer(y)});    } } Class Algorithm{ public int add(int a,int b){ return a + b; } }

現在開始對java反射機製做簡單的介紹

JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法;這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制.

Java反射機制主要提供了以下功能: 在運行時判斷任意一個對象所屬的類;在運行時構造任意一個類的對象;在運行時判斷任意一個類所具有的成員變數和方法;在運行時調用任意一個對象的方法;生成動態代理.

反射,從這個“反”字可以看出與我們平時正常的使用邏輯肯定不一樣,那麼到底什麼地方不一樣了?想要瞭解“反”,就得先瞭解一下“正”的概念。

在正常情況下,如果要使用一個類,必須要經過以下幾個步驟:

(1)使用important導入類所在的包(類:java.lang.Class

(2)通過關鍵字new進行類對象實例化(構造方法:java.lang.reflect.Constructor

(3)產生對象可以使用“對象.屬性”進行類中屬性的調用(屬性:java.lang.reflect.Field)

(4)通過“對象.方法()”調用類中的方法(方法:java.lang.reflect.Method

括弧中的紅色字體是每個步驟對應反射中使用到的類,如果現在不瞭解,可以先不用管,後面會一一介紹,這裡是為了方便進行比較。

在反射中,使用一個類並不需要導入類的所在包,只要知道類的完整路徑就可以知道該類中的所有信息。

反射不需要有明確的類型對象,所有的對象都使用Object表示。可以直接用Object的與反射機制的混合調用類中的方法。

在認識反射機制之前,必須要介紹一下Class類,Class類是整個反射操作的源頭,該類的定義如下:

public final class Class<T>  extends Object  implements Serializable, GenericDeclaration, Type, AnnotatedElement 

Class類的實例表示正在運行的Java應用程式中的類和介面。

如果要想使用Class類進行操作,就必須首先產生Class類這個對象,一共有三種方法:

(1)Object類中提供了一個返回Class類的方法,定義如下:

     public final Class<?> getClass()  

(2)利用“類.class”取得。

(3)利用Class類的Static方法取得。

      public static Class<?> forName(String className)  throws ClassNotFoundException 

在程式開發過程中,使用第二種方法比較多。但是在程式框架設計中,都是使用第三種方法,也就是反射機制用到的方法。

class類實例化對象:

Class類如果使用forName()方法之後,就可以調用Class類中newInstance()無參構造函數方法進行操作,該方法定義如下:

        public T newInstance()  throws InstantiationException, IllegalAccessException

該方法表示創建此Class對象所表示的類的一個新實例, 使用方法如下:

class Student {

    public Student() {
         System.out.println("Student類的構造方法");
     }

    @Override
     public String toString() {
         return "Student類的toString方法";
     }
}

public class ReflectDemo {

    public static void main(String[] args) throws Exception {
         Class<?> cls = Class.forName("com.iflytek.Student");
         // 相當於關鍵字實例化對象,Object obj = new Student();
         Object obj = cls.newInstance();
         System.out.println(obj);
     }

}

輸出的結果是:

Student類的構造方法 

Student類的toString方法

通過上面的實例可以看出,調用newInstace()方法時,程式會預設調用Student類的無參構造方法,並且獲取到了Student類的實例化對象,可以調用Student類裡面的方法屬性。

 

在Class類中有兩個方法可以獲取類中的構造方法,分別是

獲取類中所有的構造方法:

public Constructor<?>[] getConstructors()  throws SecurityException 

獲取類中指定的構造方法:

public Constructor<T> getConstructor(Class<?>... parameterTypes)  throws NoSuchMethodException, SecurityException 

下麵是測試例子:

public class ReflectStringDemo {
     public static void main(String[] args) throws Exception{
         Class<?> cls = Class.forName("java.lang.String");
         //獲取所有構造函數
         Constructor<?>[] cons = cls.getConstructors();
         //迴圈列印
         for (int i = 0; i < cons.length; i++) {
             System.out.println(cons[i]);
         }
     }
}

列印結果:

public java.lang.String(byte[])
public java.lang.String(byte[],int,int)
public java.lang.String(byte[],java.nio.charset.Charset)
public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException
public java.lang.String(byte[],int,int,java.nio.charset.Charset)
public java.lang.String(java.lang.StringBuilder)
public java.lang.String(java.lang.StringBuffer)
public java.lang.String(int[],int,int)
public java.lang.String(char[],int,int)
public java.lang.String(char[])
public java.lang.String(java.lang.String)
public java.lang.String()
public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException
public java.lang.String(byte[],int)
public java.lang.String(byte[],int,int,int)

上面實例獲取了String類中的所有構造方法,包括構造方法中的參數、異常等

獲取所有構造方法看上去並不難,如果想要進行指定構造方法的調用,則必須關註Constructor類,使用newInstance()方法進行實例

public T newInstance(Object... initargs) throws  

            InstantiationException,IllegalAccessException,IllegalArgumentException,InvocationTargetException

下麵是測試例子:

import java.lang.reflect.Constructor;

class Student2 {
     private String name;

    private Integer age;

    public Student2(String name, Integer age) {
         this.name = name;
         this.age = age;
     }

    @Override
     public String toString() {
         return "name:" + this.name + ";age:" + this.age;
     }
}

public class ReflectConstructorDemo {

    public static void main(String[] args) throws Exception {
         Class<?> cls = Class.forName("com.iflytek.Student2");
         Constructor<?> con = cls.getConstructor(String.class, Integer.class);
         // 這裡就相當於Object obj = new Student2("xyz",20);
         Object obj = con.newInstance("xyz", 20);
         System.out.println(obj);
     }

}

結果:

name:xyz;age:20

通過上面可以看出,如果要實例化一個對象,使用無參構造方法比有參構造方法簡單的多,使用無參直接調用newInstance()方法,使用有參則先獲取有參構造方法,

再通過Constructor中的newInstance()方法,並用指定的初始化參數初始化改實例。很多框架中的底層代碼預設都是使用無參構造方法來實例化對象,

所以在簡單Java類開發中都要明確給出無參構造方法.

 

獲取類中的方法可以分為兩大類,每個大類中又可以分為兩小類,風別是:

獲取包括父類集成而來的方法:

獲取全部方法:

public Method[] getMethods()  throws SecurityException 

獲取指定方法:

public Method getMethod(String name,Class<?>... parameterTypes)  throws NoSuchMethodException, SecurityException 

獲取本類中定義的方法:

    獲取全部方法:

    public Method[] getDeclaredMethods()  throws SecurityException 

    獲取指定方法:

    public Method getDeclaredMethod(String name, Class<?>... parameterTypes)  throws NoSuchMethodException, SecurityException 

下麵是測試例子:

import java.lang.reflect.Method;
class Student3{
     public void fun(){};
     public void talk(){};
}
public class ReflectMethodStuDemo {
     public static void main(String[] args) throws ClassNotFoundException{
         Class<?> cls = Class.forName("com.iflytek.Student3");
         //獲取本類中定義的方法
         Method[] method = cls.getDeclaredMethods();
         //迴圈列印
         for (int i = 0; i < method.length; i++) {
             System.out.println(method[i]);
         }
     }
}

列印結果:

public void com.iflytek.Student3.fun() 

public void com.iflytek.Student3.talk()

如果把上述代碼中的getDeclaredMethods()換成getMethods(),列印出來的結果如下

public void com.iflytek.Student3.fun()
public void com.iflytek.Student3.talk()

public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

使用getMethods()方法時,不僅獲取到了Student3類中的方法(紅色字體),Object類中的所有方法也被獲取到.

上面的程式是直接調用了Method類中的toString()方法輸出的,輸出格式並不是很理想,沒有異常等相關信息。如果有需要,我們也可以自己整理拼接方法輸出。

需要用到Method類中的如下幾種方法:

getModifiers():以整數形式返回此 Method 對象所表示方法的 Java 語言修飾符。

getReturnType():返回一個 Class 對象,該對象描述了此Method 對象所表示的方法的正式返回類型。

getName():以 String 形式返回此 Method 對象表示的方法名稱。

getParameterTypes():按照聲明順序返回 Class 對象的數組,這些對象描述了此Method 對象所表示的方法的形參類型。

getExceptionTypes():返回 Class 對象的數組,這些對象描述了聲明將此Method 對象表示的底層方法拋出的異常類型。

在這需要註意的是,利用getModifiers()獲取修飾符並不是簡單的輸出public、static等,而是以整數形式返回所表示的方法的Java語言修飾符。

可藉助Modifier類的toString()方法來完成。

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
interface Message {
     public void get();
}
class Student1 implements Message {
     public void fun() {
     }
     public void print() {
     }
     public void get() {
     }
}

public class ReflectMethodDemo {
     public static void main(String[] args) throws Exception {
         Class<?> cls = Class.forName("com.iflytek.Student1");
         Method[] me = cls.getMethods();
         for (int i = 0; i < me.length; i++) {
             // 此時用了method的toString方法輸出,如果有需要,用戶也可以自己拼湊輸出
             // System.out.println(me[i]);
             // 取得修飾符
             System.out.print(Modifier.toString(me[i].getModifiers()) + " ");
             // 取得返回值類型
             System.out.print(me[i].getReturnType().getSimpleName() + " ");
             // 取得方法名稱
             System.out.print(me[i].getName() + "(");
             // 取得方法參數
             Class<?> params[] = me[i].getParameterTypes();
             if (params.length > 0) {
                 for (int j = 0; j < params.length; j++) {
                     System.out.print(params[j].getSimpleName() + " arg-" + j);
                     if (j < params.length - 1) {
                         System.out.print(", ");
                     }
                 }
             }
             System.out.print(") ");
             // 取得異常
             Class<?>[] exp = me[i].getExceptionTypes();
             if (exp.length > 0) {
                 System.out.print("throws ");
                 for (int j = 0; j < exp.length; j++) {
                     System.out.print(exp[j].getSimpleName());
                     if (j < exp.length - 1) {
                         System.out.println(", ");
                     }
                 }
             }
             System.out.println("{}");
             System.out.println();
         }
     }
}

列印結果:

public void get() {}
public void print() {}
public void fun() {}
public final void wait(long arg-0, int arg-1) throws InterruptedException{}
public final native void wait(long arg-0) throws InterruptedException{}
public final void wait() throws InterruptedException{}
public boolean equals(Object arg-0) {}
public String toString() {}
public native int hashCode() {}
public final native Class getClass() {}
public final native void notify() {}
public final native void notifyAll() {}

 

調用(invoke):對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法。

public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException

該方法的英文名字是invoke,中文名稱就叫“調用”,該方法在Method類中,Method類本身就代表一個方法,當Method類中的對象調用invoke方法時,

就相當於調用了Method對象所代表的方法,方法裡面傳入對應的參數,實現動態調用方法。這裡可能比較難理解,看一下一個簡單的實例:

import java.lang.reflect.Method;
class Student4 {
     private String name;
     public String getName() {
         return name;
     }
     public void setName(String name) {
         this.name = name;
     }
}
public class ReflectInvokeDemo {
     public static void main(String[] args) throws Exception {
         Class<?> cls = Class.forName("com.iflytek.Student4");
         // 實例化對象
         Object obj = cls.newInstance();
         //獲取setName()方法
         Method setNameMethod = cls.getMethod("setName", String.class);
         //獲取getName()方法
         Method getNameMethod = cls.getMethod("getName");
         //調用setName()方法,相當於 對象.setName("xyz");
         setNameMethod.invoke(obj, "xyz");
         //調用getName()方法並輸出
         System.out.println(getNameMethod.invoke(obj));
     }
}

註意上面紅色字體的代碼

 

調用類中的屬性和調用類中的方法差不多,也是分為兩大類,每個大類裡面分為兩小類,如下:

獲取包括繼承而來的屬性:

獲取全部屬性:

public Field[] getFields()  throws SecurityException 

獲取指定屬性:

public Field getField(String name)  throws NoSuchFieldException,  SecurityException 

獲取本類定義的屬性:

        獲取全部屬性:

public Field[] getDeclaredFields()  throws SecurityException 

        獲取指定的屬性:

public Field getDeclaredField(String name)  throws NoSuchFieldException,  SecurityException 

利用反射獲取類中的屬性,是不提倡使用的,因為違背了面向對象的封裝特性
在Field類中定義了進行屬性調用的方法:

設置屬性內容:

public void set(Object obj, Object value)  throws IllegalArgumentException, IllegalAccessException 

獲取屬性類容:

public Object get(Object obj)  throws IllegalArgumentException, IllegalAccessException 

實例:

import java.lang.reflect.Field;
class Student5 {
     private String name;
}
public class ReflectFiledDemo {
     public static void main(String[] args) throws Exception {
         Class<?> cls = Class.forName("com.iflytek.Student5");
         //實例化
         Object obj = cls.newInstance();
         //獲取屬性
         Field nameField = cls.getDeclaredField("name");
         //取消訪問檢查
         <strong>nameField.setAccessible(true);</strong>
         //給屬性賦值
         nameField.set(obj, "馬小超");
         //獲取屬性值並輸出
         System.out.println(nameField.get(obj));
     }
}

大家在閱讀上面代碼時會看到有一行代碼被加粗標紅了,為什麼了?原因是Student類中的name屬性是private屬性的,不對外開放,如果Field類直接訪問該屬性,

會報許可權錯誤。

在Construction,Method,Field三個類中有一個共同的父類AccessibleObject,定義了取消封裝的操作:setAccessible(Boolean flag)

public void setAccessible(boolean flag)  throws SecurityException 

該方法預設的是參數是false,表示反射的對象應該實施 Java 語言訪問檢查。值為 true 則指示反射的對象在使用時應該取消 Java 語言訪問檢查。

 

得到某個類的靜態屬性

public Object getStaticProperty(String className, String fieldName)
             throws Exception {
     Class ownerClass = Class.forName(className);
     Field field = ownerClass.getField(fieldName);
     Object property = field.get(ownerClass);
     return property;
}

Class ownerClass = Class.forName(className) :首先得到這個類的Class。

Field field = ownerClass.getField(fieldName):通過Class得到類聲明的屬性。

Object property = field.get(ownerClass) :這裡和上面例子有些不同,因為該屬性是靜態的,所以直接從類的Class里取。

 

執行某個類的靜態方法

public Object invokeStaticMethod(String className, String methodName,
             Object[] args) throws Exception {
     Class ownerClass = Class.forName(className);
     Class[] argsClass = new Class[args.length];
     for (int i = 0, j = args.length; i < j; i++) {
         argsClass[i] = args[i].getClass();
     }
    Method method = ownerClass.getMethod(methodName,argsClass);
     return method.invoke(null, args); 
}
 

invoke的一個參數是null,因為這是靜態方法,不需要藉助實例運行


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Getting Started Getting Started. 1 1. Introduction. 1 2.Quick Start-Strandalone HBase. 1 2.1 JDK版本選擇... 1 2.2 Get Started With HBase. 1 2.3 偽分散式本地安裝.. ...
  • 正則表達式通常稱為regexes,是文本處理中模式匹配的一個標準,也是處理字元串的一個強有力的工具。使用正則表達式時,需要指定一個字元串作為模式串去檢索目標字元串。你可以使用正則表達式來查找字元串中匹配該正則表達式表示的模式的子串,也可以進行文本替換或者從目標文本中提取子串。 參考資料《iOS編程指 ...
  • 一個曲線 圖例: 多個曲線 圖例: ...
  • 一個簡單的界面: item.xml: 代碼: 開許可權: ...
  • 首先,我們都知道NSObject是大多數類的根類,但是,這個類的是怎麼實現的呢?我們可以去下載開源的Runtime源碼,探究下NSObject類的實現。 1. NSObject.h文件 我們可以直接使用Command點NSOject進去看到它的頭文件,可以看到,NSObject.h文件中有兩塊內容: ...
  • 前言: 這篇文章是我從事ISP研究數年來的一些經驗總結,沒有用到深奧的理論知識,有的只是根據實際狀況來處理的一些常規方法,以及曾經犯過的錯誤總結。我想把ISP function的原理用簡單淺顯的語言描述出來,希望對初學者有所幫助。這裡的ISP主要是指從CMOS sensor輸出的bayer patt ...
  • 先導入 然後在 info.plist 文件中添加 Privacy - Location Always and When In Use Usage Description 和 Privacy - Location When In Use Usage Description 兩個就可以了。 Locati ...
  • 一、Android Color設置 1、在xml文件中 想設置顏色直接設置background的屬性或者其他的color屬性。隨便設置一個顏色如#000,再點擊左邊的顏色方塊,彈出顏色選擇器選擇顏色 2、在java代碼中 ①Color.parseColor("#000"); 【提示】可以在佈局文件中 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...