Java反射機制

来源:http://www.cnblogs.com/Chenjiabing/archive/2017/06/14/7011649.html
-Advertisement-
Play Games

Java反射機制 前言 更多文章請一步本人博客 "https://chenjiabing666.github.io/" "網頁版的jdk的API" "離線版API" 什麼是反射機制 反射是java語言的一個特性,它允程式在運行時(註意不是編譯的時候)來進行自我檢查並且對內部的成員進行操作。例如它允許 ...


Java反射機制

前言

什麼是反射機制

反射是java語言的一個特性,它允程式在運行時(註意不是編譯的時候)來進行自我檢查並且對內部的成員進行操作。例如它允許一個java的類獲取他所有的成員變數和方法並且顯示出來。這個能特定我們不常看到,但是在其他的比如C或者C++語言中很不就存在這個特性。一個常見的例子是在JavaBean中,一些組件可以通過一個構造器來操作。這個構造器就是用的反射在動態載入的時候來獲取的java中類的屬性的。

主要的類

  • Class 類的實例表示正在運行的 Java 應用程式中的類和介面。Class沒有公共的構造方法,Class 對象是在載入類時由 Java 虛擬機以及通過調用類載入器中的 defineClass 方法自動構造的
  • Constructor 提供關於類的單個構造方法的信息以及對它的訪問許可權(主要提供的是對構造方法使用)
  • Method 提供關於類或介面上單獨某個方法(以及如何訪問該方法)的信息。所反映的方法可能是類方法或實例方法(包括抽象方法)
  • Field 主要提供對類中的成員變數的訪問和使用

Class

Class類也使用了泛型,即是Class這種形式的,可以直接使用一個具體的類傳入,這樣的話就不需要強制轉換了,比如Class.newInstance()這樣使用預設的構造方法構造一個對象就需要不再需要強制轉換了即使用(ClassName)Class.newInstance()

常用的方法

  • getConstructor(Class[] params) 獲取公共的(public)的構造方法,並且限定其中的參數個數和類型可以獲得不同的公共構造方法
  • Constructor[] getConstructors() 返回所有的公共(public)的構造方法
  • getDeclaredConstructor(Class[] params) 獲取所有指定的構造方法,但是需要註意的是當獲取私有的構造方法的時候需要使用setAccessible設置訪問許可權為true才能進行構造,否則出現異常
  • Constructor[] getDeclaredConstructors() 返所有的構造方法包括public和private,protected修飾的
  • T newInstance() 返回的是一個調用預設的構造方法(public class_name())實例化的一個Object對象,如果使用泛型那麼就返回T類型的,反之返回的是Object需要強制轉換才能使用這個對象調用成員函數和成員變數
  • Class forName(String class_name) 返回class對象,每一個對都有一個方象法返回Class對象(test.class)
  • Package getPackage() 返回此類所在的包名(package demo) 當然也可以使用Package.getName()獲得包的名字(demo)比如constructor.getPackage().getName()
  • int getModifiers() 返回的是類的修飾符的整數 類型(修飾符的類型有public private protected)其中得到整數可以使用Modifier中toString(int num)得到public,private,protected的類型,比如Modifier.toString(class1.getModifiers())
    * Method getMethod(String name, Class<?>... parameterTypes) 返回指定參數的方法Method對象,註意這裡僅僅是返回的時公共的方法(public) 比如:Method method=class1.getMethod("display",new Class[]{int.class})這裡的display是方法的名字,有一個參數,類型為int
  • Method[] getMethods() 獲取所有的公共的方法(public)返回的是一個數組(Method)
  • Method getDeclaredMethod(String name,Class<?>... parameterTypes)返回所有的指定的參數的方法(public,private,protected,但是不包括繼承的),其中參數可以為null(無參數)
  • Method[] getDeclaredMethods() 獲取所有的方法
  • Field getField(String name) 指定名字的公共成員變數(public)
  • Field[] getFields() 獲取所有的公共的成員變數
  • Field getDeclaredField(String name) 獲取所有的指定名稱的成員變數(public,protected,private),同樣在調用私有成員變數的時候需要先設置訪問的許可權,field.setAccessible(true)
  • Field[] getDeclaredFields() 獲取所有的成員變數(public,protected,private)
  • getSuperclass() 返回表示此 Class 所表示的實體(類、介面、基本類型或 void)的超類的 Class。
  • URL getResource(String name) 查找指定名稱的資源(圖片,文件...)註意這個資源一定要和指定類在一個包中,否則返回null,比如查找Test類下的airplane.png圖片:Test.class.getResource("airplane.png")這裡返回的將是絕對路徑

獲取Class的對象並且實例化

  • 使用Class.forName(String className) 其中className一定是包含包的名字,下麵的demo就是包的名字,Test是類的名字。這是最常用的方法,學過JDBC的都知道載入驅動的時候就是使用的Class.forName()
    /*
     * 第一種使用forName(String className),其中className一定是包含包的名字,下麵的demo就是包的名字,Test是類的名字
     */
    Class cls=Class.forName("demo.Test");
    Test test=(Test)cls.newInstance();    //這裡只是使用了預設的構造方法實例化對象
    
  • 使用類名.class
    Class cls=Test.class;
  • 使用對象.getClass()
    Test test=new Test();
    Class cls=test.getClass();   

Constructor

  • 主要是用來對類的構造方法進行操作的,可以看出這個也使用了泛型,和上面的Class是一樣的,註意這裡如果沒有使用泛型,那麼原本放回T類型的現在都是返回Object

常用的方法

  • T newInstance(Object parms) 使用帶有參數的構造方法實例化對象,如果使用了泛型,那麼返回的就是T類型的,反之返回的是Object類型的,需要強制轉換
  • getName() 以字元串的形式返回構造方法的名稱,具體的路徑包含包名(demo.Test)
  • int getModifiers()Class類中的方法一樣

Method

主要提供的是對類中的方法的操作

常用的方法

  • Object invoke(Object obj,object args) 使用得到的Method對象調用方法,obj是類的已經構造好的對象,如果是靜態方法直接寫null,因為靜態方法的調用不需要對象,返回值是Object類型的,如果接受返回值,需要使用強制轉換成相應的類型,args是傳入的參數,如果有多個參數,那麼可以直接在後面用逗號添加或者直接創建數組new Object[]{22,"chenjiabing"}比如:method.invoke(test,22,"chenjiabing") method.invoke(test,new Object[]{22,"chenjiabing"})註意:如果調用的private類型的方法,那麼需要在前面設置訪問的許可權,method.setAccessible(true)
  • String getName() 返回此方法的名字(display)
  • Modifier getModifiers() 返回此方法的修飾符的類型表示的整數(public,private...),可以使用Modifier.toString()轉換成字元串形式
  • Class getReturnType() 返回這個方法的返回類型
  • String toString() 返回這個方法表示的字元串的形式

Field

主要提供對類的成員變數的操作

常用方法

  • String getName() 返回變數名字
  • Object get(Object obj) 返回此變數在指定對象中的值,因為在構造對象的時候每一個傳入的變數的值都不一樣,因此需要使用對象obj。obj表示傳入的對象,返回的Object類型,因此需要強制轉換
  • void set(Object obj,Object value) 改變obj對象上的變數的值為value
  • Modifier getModifiers() 返回整數表示修飾的類型
  • String getType() 獲取變數的類型(int,String,double float.....)

Modifier

Modifier 類提供了 static 方法和常量,對類和成員訪問修飾符進行解碼。修飾符集被表示為整數,用不同的位位置 (bit position) 表示不同的修飾符。

常用的方法

  • static String toString(int mode) 將代表修飾符的整數形式轉換為字元串形式的修飾符,比如將1轉換成public
  • static isInterface(int mode) 如果整數參數包括 interface 修飾符,則返回 true,否則返回 false
  • static isStatic(int mode)
  • static isPrivate(int mode)
  • static isPublic(int mode)
  • static isAbstract(int mode)

實例

     Modifier.toString(Test.class.getModifiers())    //得到Test類的修飾符

使用

有了上面的鋪墊,我們就可以使用上面的這些類進行操作了,在進行操作之前,我們需要先定義一個類Test,放在demo包下,內容如下

package demo;

import java.util.jar.Attributes.Name;

import javax.print.attribute.standard.MediaSize.NA;

public class Test {
	public String name;
	private int age;

	public Test() {
		this.name = "陳加兵";
		this.age = 23;
	}

	public Test(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public void display() {
		System.out.println("name=" + this.name + "----age=" + this.age);
	}

	public void set(String name, int age) {
		this.name = name;
		this.age = age;
	}

	private int getAge() {
		return this.age;
	}

}

實例化對象

  • 使用Class預設的構造newInstance()
        Class class1=Class.forName("demo.Test");  //靜態載入Class
		Test test=(Test)class1.newInstance();  //調用預設的構造方法(public Test())實例化對象,由於沒有使用泛型,因此需要強轉
		test.display();    //調用display方法

  • 使用Class中的getConstructor()方法構造對象,需要註意的使用private類型構造方法時一定要先設置訪問許可權為true-constructor.setAccessible(true);
        /*
		 *調用public Test(String name,int age)得到Constructor的兩種形式
		 *   1.Constructor constructor=class1.getConstructor(new Class[]{String.class,int.class});
		 *   2.Constructor constructor=class1.getConstructor(String.class,int.class);這個和上面的是一樣的,就是使用的參數形式不一樣
		 * 
		 * 
		 * 
		 * 
		 *使用newInstance()構造對象的兩種方式
		 *   1.Test test=(Test)constructor.newInstance(new Object[]{"chenjiabing",22});
		 *	 2.Test test=(Test)constructor.newInstance("chenjiabing",22); 只是形式不同而已,不過我還是喜歡上面的形式
		 *
		 */
		
		
		
		
		/*
		 * 調用public Test(String name,int age)
		 * 		Class.getConstructor()得到的是公共的構造方法,如果有私有的構造方法,那麼就會報錯,這時就要使用getDeclaredConstructor(Class<?>... parameterTypes)
		 * 		Test test=(Test)constructor.newInstance("陳加兵",22);
		 * 
		 * 
		 * 調用public Test() 
		 *  	Constructor constructor=class1.getConstructor(null);
		 *  	Test test=(Test)constructor.newInstance(null);
		 * 
		 * 
		 * 調用private Test(int age)
		 * 		Constructor constructor=class1.getDeclaredConstructor(new Class[]{int.class});
				constructor.setAccessible(true);   //因為private類型是不可以直接訪問的,因此需要設置訪問許可權為true
				Test test=(Test)constructor.newInstance(new Object[]{1000});
		*/
		
        
        
        Class class1=Class.forName("demo.Test");
		//訪問public Test(String name,int age)
//		Constructor constructor=class1.getConstructor(new Class[]{String.class,int.class});
//		Test test=(Test)constructor.newInstance("陳加兵",22);
		
		//訪問預設的構造方法
//		Constructor constructor=class1.getConstructor(null);
//		Test test=(Test)constructor.newInstance(null);

		//訪問private類型的構造方法
		Constructor constructor=class1.getDeclaredConstructor(new Class[]{int.class});
		constructor.setAccessible(true);
		Test test=(Test)constructor.newInstance(new Object[]{1000});
		test.display();
		

成員方法的操作

使用Class.getMethod()Class.getDeclaredMethod()方法獲取方法,這兩個方法的區別前面已經說過了,註意的是調用私有成員方法的之前一定要設置訪問許可權(method.setAccessible(true))

Method類中的其他方法前面也已經說過了,詳細使用請自己嘗試

		/*
		 * 獲取Method對象的兩種方式:
		 * 		1.Method method_set=class1.getMethod("set", new Class[]{String.class,int.class});
		 * 		2.Method method_set=class1.getMethod("set", String.class,int.class);
		 * 
		 * 
		 * 使用Method.invoke()調用方法的兩種方式
		 * 		1.Object o=method_set.invoke(test, new Object[]{"陳加兵",200});
		 * 		2.Object object=method_set.invoke(test, "陳加兵",2000);
		 */
		
        
        
        
		/*
		 * 獲取公共方法(public):
		 * 		1.Method method=class1.getMethod("display",null);  //public void display()
		 * 		2.Method method_set=class1.getMethod("set", new Class[]{String.class,int.class});  //獲取public void set(String name,int age)
		 * 
		 * 
		 * 獲取私有方法(private,protected)
		 * 		1.Method method_getAge=class1.getDeclaredMethod("getAge", null);
		 */
		
		
		//使用構造方法構造一個Test對象
		Class class1 =Class.forName("demo.Test");
		Constructor<Test> constructor=class1.getDeclaredConstructor(new Class[]{String.class,int.class});
		Test test=constructor.newInstance(new Object[]{"陳加兵",22});
		
		
		Method method=class1.getMethod("display",null);   //獲取public void display()方法的Method對象
		Object obj=method.invoke(test, null);    //調用方法display
		
		//獲取public void set(String name,int age)
//		Method method_set=class1.getMethod("set", new Class[]{String.class,int.class});
		Method method_set=class1.getMethod("set", String.class,int.class);
		
//		Object o=method_set.invoke(test, new Object[]{"陳加兵",200});
		Object object=method_set.invoke(test, "陳加兵",2000);
		test.display();
		
		
		//獲取私有方法private int getAge()
		Method method_getAge=class1.getDeclaredMethod("getAge", null);
		method_getAge.setAccessible(true);   //必須設置訪問許可權為true
		//判斷返回值類型是否為int類型的
		if("int".equals(method_getAge.getReturnType().toString()))
		{
			int ReturnData=(int) method_getAge.invoke(test, null);   //調用並且獲取返回值
			System.out.println(ReturnData);
		}
		

成員變數的操作

主要使用的Field類,前面已經詳細的說過了

/*
		 * 獲取public修飾的成員變數:
		 * 		1.Field field=class1.getField("name"); //獲取public的成員變數name的Filed對象
		 * 
		 * 獲取private,protected修飾的成員變數:
		 * 		1.	Field field2=class1.getDeclaredField("age");
		 */
         
         
		Class class1=Class.forName("demo.Test");
		Test test=new Test("陳加兵",1000);
		Field field=class1.getField("name"); //獲取public的成員變數name的Filed對象
		System.out.println(field.get(test));   //獲得test對象中的name屬性的值
		
		//獲取private int age的Field對象
		Field field2=class1.getDeclaredField("age");
		field2.setAccessible(true);  //設置訪問許可權
		System.out.println(field2.get(test));

參考文章

如果覺得作者寫的好,有所收穫的話,點個關註,推薦一波,文章首發於公眾號!!!
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • POJO(Plain Ordinary Java Object)即普通Java類,具有一部分getter/setter方法的那種類就可以稱作POJO。 實際意義就是普通的JavaBeans(簡單的實體類),特點就是支持業務邏輯的協助類。 POJO類的作用是方便程式員使用資料庫中的數據表,對於程式員來 ...
  • JAVA學習路線圖,特此聲明; 僅希望對熱愛JAVA學習有所幫助 如若轉載或者使用本圖,請註明出處,避免後期出現版權問題,謝謝!!! JAVA學習路線圖此乃是java攻城獅的學習路線圖,由簡到繁,由易到難,一步步的學習,最後成為JAVA攻城獅。希望對大家的學習有所幫助階段1 1:學習HTML 2:學 ...
  • HTTP協議: HTTP(Hypertext Transfer Protocol):即超文本傳輸協議。URL是通過HTTP協議存取資源的Internet路徑,一個URL對應一個數據資源。 HTTP協議對資源的操作: Requests庫提供了HTTP所有的基本請求方式。官方介紹:http://www. ...
  • 轉載:http://aguang520.iteye.com/blog/1056686 ...
  • 轉載請註明出處:http://www.cnblogs.com/Joanna-Yan/p/7010201.html 前面講到:Spring+SpringMVC+MyBatis深入學習及搭建(十二)——SpringMVC入門程式(一) 1.非註解的處理器映射器和適配器 1.1非註解的處理器映射器 前面我 ...
  • java字元串的功能可以說非常強大, 它的每一種方法也都很有用. java字元串中常用的有兩種字元串類, 分別是String類和StringBuffer類. Sting類 String類的對象是不可變的. 創建String 常用方法 實例: 比較性質的方法 查找方法 替換方法 其他方法 將數字化的字 ...
  • Python的Excel操作需要另外下載安裝對應Python版本的xlrd和xlwt包,用於對Excel的讀取和寫入。 安裝方法:直接解壓後,在字元命令界面cd到setup.py的目錄,執行命令“Python setup.py install”即可。 xlrd(下麵有些是方法,有些是屬性,屬性後面不 ...
  • 最近想學習一些python數據分析的內容,就弄了個爬蟲爬取了一些數據,並打算用Anaconda一套的工具(pandas, numpy, scipy, matplotlib, jupyter)等進行一些初步的數據挖掘和分析。 在使用matplotlib畫圖時,橫坐標為中文,但是畫出的條形圖橫坐標總是顯 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...