生活随笔
收集整理的這篇文章主要介紹了
java原理—反射机制
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
http://www.cnblogs.com/forlina/archive/2011/06/21/2085849.html
一、什么是反射:
反射的概念是由Smith在1982年首次提出的,主要是指程序可以訪問、檢測和修改它本身狀態或行為的一種能力。這一概念的提 出很快引發了計算機科學領域關于應用反射性的研究。它首先被程序語言的設計領域所采用,并在Lisp和面向對象方面取得了成績。其中 LEAD/LEAD++ 、OpenC++ 、MetaXa和OpenJava等就是基于反射機制的語言。最近,反射機制也被應用到了視窗系統、操作系統和文件系統中。
反射本身并不 是一個新概念,盡管計算機科學賦予了反射概念新的含義。在計算機科學領域,反射是指一類應用,它們能夠自描述和自控制。也就是說,這類應用通過采用某種機 制來實現對自己行為的描述(self-representation)和監測(examination),并能根據自身行為的狀態和結果,調整或修改應用 所描述行為的狀態和相關的語義。
二、什么是Java中的類反射:
Reflection 是 Java 程序開發語言的特征之一,它允許運行中的 Java 程序對自身進行檢查,或者說“自審”,并能直接操作程序的內部屬性和方法。Java 的這一能力在實際應用中用得不是很多,但是在其它的程序設計語言中根本就不存在這一特性。例如,Pascal、C 或者 C++ 中就沒有辦法在程序中獲得函數定義相關的信息。
Reflection 是 Java 被視為動態(或準動態)語言的關鍵,允許程序于執行期 Reflection APIs 取得任何已知名稱之 class 的內部信息,包括 package、type parameters、superclass、implemented interfaces、inner classes, outer class, fields、constructors、methods、modifiers,並可于執行期生成instances、變更 fields 內容或喚起 methods。
三、Java類反射中所必須的類:
Java的類反射所需要的類并不多,它們分別是:Field、Constructor、Method、Class、Object,下面我將對這些類做一個簡單的說明。
Field類:提供有關類或接口的屬性的信息,以及對它的動態訪問權限。反射的字段可能是一個類(靜態)屬性或實例屬性,簡單的理解可以把它看成一個封裝反射類的屬性的類。
Constructor類:提供關于類的單個構造方法的信息以及對它的訪問權限。這個類和Field類不同,Field類封裝了反射類的屬性,而Constructor類則封裝了反射類的構造方法。
Method類:提供關于類或接口上單獨某個方法的信息。所反映的方法可能是類方法或實例方法(包括抽象方法)。 這個類不難理解,它是用來封裝反射類方法的一個類。
Class類:類的實例表示正在運行的 Java 應用程序中的類和接口。枚舉是一種類,注釋是一種接口。每個數組屬于被映射為 Class 對象的一個類,所有具有相同元素類型和維數的數組都共享該 Class 對象。
Object類:每個類都使用 Object 作為超類。所有對象(包括數組)都實現這個類的方法。
四、Java的反射類能做什么:
看完上面的這么多我想你已經不耐煩了,你以為我在浪費你的時間,那么好吧!下面我們就用一些簡單的小例子來說明它。
首先我們來看一下通過Java的反射機制我們能得到些什么。
首先我們來寫一個類:
java 代碼
import?java.awt.event.ActionListener;??import?java.awt.event.ActionEvent;??class?A?extends?Object?implements?ActionListener{??private?int?a?=?3;??public?Integer?b?=?new?Integer(4);??public?A(){}??public?A(int?id,String?name){}??public?int?abc(int?id,String?name){return?0;}??public?void?actionPerformed(ActionEvent?e){}??}??
你可能被我這個類弄糊涂了,你看不出我要做什么,那就不要看這個類了,這個類是用來測試的,你知道知道它繼承了Object類,有一個接口是ActionListener,兩個屬性int和Integer,兩個構造方法和兩個方法,這就足夠了。
下面我們把A這個類作為一個反射類,來過去A類中的一些信息,首先我們先來過去一下反射類中的屬性和屬性值。
java 代碼
import?java.lang.reflect.*;??class?B{??public?static?void?main(String?args[]){??A?r?=?new?A();??Class?temp?=?r.getClass();??try{??System.out.println("反射類中所有公有的屬性");??Field[]?fb?=temp.getFields();??for(int?j=0;j<fb.length;j++){??Class?cl?=?fb[j].getType();??System.out.println("fb:"+cl);??}????System.out.println("反射類中所有的屬性");??Field[]?fa?=?temp.getDeclaredFields();??for(int?j=0;j<fa.length;j++){??Class?cl?=?fa[j].getType();??System.out.println("fa:"+cl);??}??System.out.println("反射類中私有屬性的值");??Field?f?=?temp.getDeclaredField("a");??f.setAccessible(true);??Integer?i?=?(Integer)f.get(r);??System.out.println(i);??}catch(Exception?e){??e.printStackTrace();??}??}????}???
這 里用到了兩個方法,getFields()、getDeclaredFields(),它們分別是用來獲取反射類中所有公有屬性和反射類中所有的屬性的方 法。另外還有getField(String)和getDeclaredField(String)方法都是用來過去反射類中指定的屬性的方法,要注意的 是getField方法只能取到反射類中公有的屬性,而getDeclaredField方法都能取到。
這里還用到了Field 類的setAccessible方法,它是用來設置是否有權限訪問反射類中的私有屬性的,只有設置為true時才可以訪問,默認為false。另外 Field類還有set(Object AttributeName,Object value)方法,可以改變指定屬性的值。
下面我們來看一下如何獲取反射類中的構造方法
java 代碼
import?java.lang.reflect.*;??public?class?SampleConstructor?{??public?static?void?main(String[]?args)?{??A?r?=?new?A();??printConstructors(r);??}????public?static?void?printConstructors(A?r)?{??Class?c?=?r.getClass();??String?className?=?c.getName();??try?{??Constructor[]?theConstructors?=?c.getConstructors();??for(int?i=0;?i<theConstructors.length;?i++)?{??Class[]?parameterTypes?=?theConstructors[i].getParameterTypes();????System.out.print(className?+?"(");????for(int?j=0;?j<parameterTypes.length;?j++)??System.out.print(parameterTypes[j].getName()?+?"?");????System.out.println(")");????}??}catch(Exception?e)?{??e.printStackTrace();??}??}??}?? 這個例子很簡單,只是用getConstructors()方法獲取了反射類的構造方法的集合,并用Constructor類的getParameterTypes()獲取該構造方法的參數。
下面我們再來獲取一下反射類的父類(超類)和接口
java 代碼
import?java.io.*;??import?java.lang.reflect.*;????public?class?SampleInterface?{??public?static?void?main(String[]?args)?throws?Exception?{??A?raf?=?new?A();??printInterfaceNames(raf);??}????public?static?void?printInterfaceNames(Object?o)?{??Class?c?=?o.getClass();??Class[]?theInterfaces?=?c.getInterfaces();??for(int?i=0;?i<theInterfaces.length;?i++)??System.out.println(theInterfaces[i].getName());??Class?theSuperclass?=?c.getSuperclass();??System.out.println(theSuperclass.getName());??}??}??
這 個例子也很簡單,只是用Class類的getInterfaces()方法獲取反射類的所有接口,由于接口可以有多個,所以它返回一個 Class數組。用getSuperclass()方法來獲取反射類的父類(超類),由于一個類只能繼承自一個類,所以它返回一個Class對象。
下面我們來獲取一下反射類的方法
java 代碼
import?java.lang.reflect.*;??public?class?SampleMethod?{????public?static?void?main(String[]?args)?{??A?p?=?new?A();??printMethods(p);??}????public?static?void?printMethods(Object?o)?{??Class?c?=?o.getClass();??String?className?=?c.getName();??Method[]?m?=?c.getMethods();??for(int?i=0;?i<m.length;?i++)?{??System.out.print(m[i].getReturnType().getName());??System.out.print("?"+m[i].getName()+"(");??Class[]?parameterTypes?=?m[i].getParameterTypes();??for(int?j=0;?j<parameterTypes.length;?j++){??System.out.print(parameterTypes[j].getName());??if(parameterTypes.length>j+1){??System.out.print(",");??}??}????System.out.println(")");??}????}????}??
這個例子并不難,它只是獲得了反射類的所有方法,包括繼承自它父類的方法。然后獲取方法的返回類型、方法名和方法參數。
接下來讓我們回過頭來想一想,我們獲取了反射類的屬性、構造方法、父類、接口和方法,可這些東西能幫我們做些什么呢!!
下面我寫一個比較完整的小例子,來說明Java的反射類能做些什么吧!!
java 代碼
import?java.lang.reflect.Constructor;??import?java.lang.reflect.Method;????public?class?LoadMethod?{??public?Object?Load(String?cName,String?MethodName,String[]?type,String[]?param){??Object?retobj?=?null;??try?{??Class?cls?=?Class.forName(cName);????Constructor?ct?=?cls.getConstructor(null);??Object?obj?=?ct.newInstance(null);????Class?partypes[]?=?this.getMethodClass(type);????Method?meth?=?cls.getMethod(MethodName,?partypes);????Object?arglist[]?=?this.getMethodObject(type,param);????retobj=?meth.invoke(obj,?arglist);????}??catch?(Throwable?e)?{??System.err.println(e);??}??return?retobj;??}????public?Class[]?getMethodClass(String[]?type){??Class[]?cs?=?new?Class[type.length];??for?(int?i?=?0;?i?<?cs.length;?i++)?{??if(!type[i].trim().equals("")||type[i]!=null){??if(type[i].equals("int")||type[i].equals("Integer")){??cs[i]=Integer.TYPE;??}else?if(type[i].equals("float")||type[i].equals("Float")){??cs[i]=Float.TYPE;??}else?if(type[i].equals("double")||type[i].equals("Double")){??cs[i]=Double.TYPE;??}else?if(type[i].equals("boolean")||type[i].equals("Boolean")){??cs[i]=Boolean.TYPE;??}else{??cs[i]=String.class;??}??}??}??return?cs;??}????public?Object[]?getMethodObject(String[]?type,String[]?param){??Object[]?obj?=?new?Object[param.length];??for?(int?i?=?0;?i?<?obj.length;?i++)?{??if(!param[i].trim().equals("")||param[i]!=null){??if(type[i].equals("int")||type[i].equals("Integer")){??obj[i]=?new?Integer(param[i]);??}else?if(type[i].equals("float")||type[i].equals("Float")){??obj[i]=?new?Float(param[i]);??}else?if(type[i].equals("double")||type[i].equals("Double")){??obj[i]=?new?Double(param[i]);??}else?if(type[i].equals("boolean")||type[i].equals("Boolean")){??obj[i]=new?Boolean(param[i]);??}else{??obj[i]?=?param[i];??}??}??}??return?obj;??}??}??
這是我在工作中寫的一個實現Java在運行時加載指定的類,并調用指定方法的一個小例子。這里沒有main方法,你可以自己寫一個。
Load方法接收的五個參數分別是,Java的類名,方法名,參數的類型和參數的值。
結束語:
Java 語言反射提供一種動態鏈接程序組件的多功能方法。它允許程序創建和控制任何類的對象,無需提前硬編碼目標類。這些特性使得反射特別適用于創建以非常普通的 方式與對象協作的庫。Java reflection 非常有用,它使類和數據結構能按名稱動態檢索相關信息,并允許在運行著的程序中操作這些信息。Java 的這一特性非常強大,并且是其它一些常用語言,如 C、C++、Fortran 或者 Pascal 等都不具備的。
但反射有兩個缺點。第一個是性能問題。用于字段和方法接入時反射要遠 慢于直接代碼。性能問題的程度取決于程序中是如何使用反射的。如果它作為程序運行中相對很少涉及的部分,緩慢的性能將不會是一個問題。即使測試中最壞情況 下的計時圖顯示的反射操作只耗用幾微秒。僅反射在性能關鍵的應用的核心邏輯中使用時性能問題才變得至關重要。
?
轉載于:https://www.cnblogs.com/zhangxia/p/4950091.html
總結
以上是生活随笔為你收集整理的java原理—反射机制的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。