轉自:http://www.cnblogs.com/bingoidea/archive/2009/06/21/1507889.htmlhtml
1、什麼是反射:
反射的概念是由Smith在1982年首次提出的,主要是指程序能夠訪問、檢測和修改它自己狀態或行爲的一種能力。這一律唸的提出很快引起了計算機科學領域關於應用反射性的研究。它首先被程序語言的設計領域所採用,並在Lisp和麪向對象方面取得了成績。其中LEAD/LEAD++ 、OpenC++ 、MetaXa和OpenJava等就是基於反射機制的語言。最近,反射機制也被應用到了視窗系統、操做系統和文件系統中。
反射自己並非一個新概念,儘管計算機科學賦予了反射概念新的含義。在計算機科學領域,反射是指一類應用,它們可以自描述和自控制。也就是說,這類應用經過採用某種機制來實現對本身行爲的描述(self-representation)和監測(examination),並能根據自身行爲的狀態和結果,調整或修改應用所描述行爲的狀態和相關的語義。
2、什麼是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。
3、Java類反射中所必須的類:
Java的類反射所須要的類並很少,它們分別是:Field、Constructor、Method、Class、Object,下面我將對這些類作一個簡單的說明。
Field類:提供有關類或接口的屬性的信息,以及對它的動態訪問權限。反射的字段多是一個類(靜態)屬性或實例屬性,簡單的理解能夠把它當作一個封裝反射類的屬性的類。
Constructor類:提供關於類的單個構造方法的信息以及對它的訪問權限。這個類和Field類不一樣,Field類封裝了反射類的屬性,而Constructor類則封裝了反射類的構造方法。
Method類:提供關於類或接口上單獨某個方法的信息。所反映的方法多是類方法或實例方法(包括抽象方法)。 這個類不難理解,它是用來封裝反射類方法的一個類。
Class類:類的實例表示正在運行的 Java 應用程序中的類和接口。枚舉是一種類,註釋是一種接口。每一個數組屬於被映射爲 Class 對象的一個類,全部具備相同元素類型和維數的數組都共享該 Class 對象。
Object類:每一個類都使用 Object 做爲超類。全部對象(包括數組)都實現這個類的方法。
4、Java的反射類能作什麼:
看完上面的這麼多我想你已經不耐煩了,你覺得我在浪費你的時間,那麼好吧!下面咱們就用一些簡單的小例子來講明它。
首先咱們來看一下經過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()獲取該構造方法的參數。
下面咱們再來獲取一下反射類的父類(超類)和接口ide
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 等都不具有的。
但反射有兩個缺點。第一個是性能問題。用於字段和方法接入時反射要遠慢於直接代碼。性能問題的程度取決於程序中是如何使用反射的。若是它做爲程序運行中相對不多涉及的部分,緩慢的性能將不會是一個問題。即便測試中最壞狀況下的計時圖顯示的反射操做只耗用幾微秒。僅反射在性能關鍵的應用的核心邏輯中使用時性能問題才變得相當重要。測試