天天看點

Java反射應用示例

一、預先需要掌握的知識(java虛拟機)

java虛拟機的方法區:

java虛拟機有一個運作時資料區,這個資料區又被分為方法區,堆區和棧區,我們這裡需要了解的主要是方法區。方法區的主要作用是存儲被裝載的類的類型資訊,當java虛拟機裝載某個類型的時候,需要類裝載器定位相應的class檔案,然後将其讀入到java虛拟機中,緊接着虛拟機提取class中的類型資訊,将這些資訊存儲到方法區中。這些資訊主要包括:

1、這個類型的全限定名

2、這個類型的直接超類的全限定名

3、這個類型是類類型還是接口類型

4、這個類型的通路修飾符

5、任何直接超接口的全限定名的有序清單

6、該類型的常量池

7、字段資訊

8、方法資訊

9、除了常量以外的所有類變量

10、一個到class類的引用

等等(讀者可以參考《深入java虛拟機》這本書的叙述)

Class類:

Class類是一個非常重要的java基礎類,每當裝載一個新的類型的時候,java虛拟機都會在java堆中建立一個對應于新類型的Class執行個體,該執行個體就代表此類型,通過該Class執行個體我們就可以通路該類型的基本資訊。上面說到在方法區中會存儲某個被裝載類的類型資訊,我們就可以通過Class執行個體來通路這些資訊。比如,對于上面說到的資訊Class中都有對應的方法,如下:

1、getName();這個類型的全限定名

2、getSuperClass();這個類型的直接超類的全限定名

3、isInterface();這個類型是類類型還是接口類型

4、getTypeParamters();這個類型的通路修飾符

5、getInterfaces();任何直接超接口的全限定名的有序清單

6、getFields();字段資訊

7、getMethods();方法資訊

等等(讀者可以自己參看jdk幫助文檔,得到更多的資訊)

二、java反射詳解

反射的概念:所謂的反射就是java語言在運作時擁有一項自觀的能力,反射使您的程式代碼能夠得到裝載到JVM中的類的内部資訊,允許您執行程式時才得到需要類的内部資訊,而不是在編寫代碼的時候就必須要知道所需類的内部資訊,這使反射成為建構靈活的應用的主要工具。

反射的常用類和函數:Java反射機制的實作要借助于4個類:Class,Constructor,Field,Method;其中class代表的是類對象,Constructor-類的構造器對象,Field-類的屬性對象,Method-類的方法對象,通過這四個對象我們可以粗略的看到一個類的各個組成部分。其中最核心的就是Class類,它是實作反射的基礎,它包含的方法我們在第一部分已經進行了基本的闡述。應用反射時我們最關心的一般是一個類的構造器、屬性和方法,下面我們主要介紹Class類中針對這三個元素的方法:

1、得到構造器的方法

Constructor getConstructor(Class[] params) -- 獲得使用特殊的參數類型的公共構造函數,

Constructor[] getConstructors() -- 獲得類的所有公共構造函數

Constructor getDeclaredConstructor(Class[] params) -- 獲得使用特定參數類型的構造函數(與接入級别無關)

Constructor[] getDeclaredConstructors() -- 獲得類的所有構造函數(與接入級别無關)

2、獲得字段資訊的方法

Field getField(String name) -- 獲得命名的公共字段

Field[] getFields() -- 獲得類的所有公共字段

Field getDeclaredField(String name) -- 獲得類聲明的命名的字段

Field[] getDeclaredFields() -- 獲得類聲明的所有字段

3、獲得方法資訊的方法

Method getMethod(String name, Class[] params) -- 使用特定的參數類型,獲得命名的公共方法

Method[] getMethods() -- 獲得類的所有公共方法

Method getDeclaredMethod(String name, Class[] params) -- 使用特寫的參數類型,獲得類聲明的命名的方法

Method[] getDeclaredMethods() -- 獲得類聲明的所有方法

應用反射的基本步驟:

1、獲得你想操作的類的Class對象;

     方法一:Class c=Class.forName("java.lang.String")

     方法二:對于基本資料類型可以用形如Class c=int.class或Class c=Integer.TYPE的語句

     方法三:Class c=MyClass.class

2、調用Class中的方法得到你想得到的資訊集合,如調用getDeclaredFields()方法得到類的所有屬性;

3、處理第2步中得到的資訊,然後進行你想做的實際操作。

反射執行個體:

下面我将針對類的構造器、屬性和方法分别舉三個例子,向大家示範一下反射的應用過程。

1、構造器

步驟為:通過反射機制得到某個類的構造器,然後調用該構造器建立該類的一個執行個體

package com.test.reflect;

import java.lang.reflect.Constructor;

public class ConstructorDemo { 
	 
	public ConstructorDemo(){  
    }  
    public ConstructorDemo(int a, int b){  
        System.out.println("a="+a+"b="+b);  
    }  
      
    public static void main(String args[]){  
        try {  
            Class cls = Class.forName("com.test.reflect.ConstructorDemo");
         
            System.out.println("class類名稱:"+cls.getName());
            Class partypes[] = new Class[2];  
            partypes[0] = Integer.TYPE;  
            partypes[1] = Integer.TYPE;  
              
            Constructor ct= cls.getConstructor(partypes);  
            Constructor[] c=cls.getConstructors();
            Object arglist[] = new Object[2];  
            arglist[0] = new Integer(37);  
            arglist[1] = new Integer(47);  
            Object retobj = ct.newInstance(arglist); 
            System.out.println("特定構造器對象:"+retobj); 
        }  
        catch (Throwable e) {  
            System.err.println(e);  
        }  
    }  

}           

2、字段屬性

步驟為:通過反射機制得到某個類的某個屬性,然後改變對應于這個類的某個執行個體的該屬性值

package com.test.reflect;

import java.lang.reflect.Field;


public class FieldDemo {
	public int a=7;
	public int d=9;
	private int b=12;
	/**
	 * @param args
	 */
	public static void main(String[] args) {
	try {
			Class cls=Class.forName("com.test.reflect.FieldDemo");
			//public類型屬性
			Field f=cls.getField("a"); 
			System.out.println("特定屬性:"+f);
			Field[] fd= cls.getFields();
			System.out.println("所有public類型屬性"+fd.length);
			//所有級别屬性
			Field fld=cls.getDeclaredField("b");
			System.out.println("private類型屬性:"+fld);
			Field[] fldd= cls.getDeclaredFields();
			System.out.println("所有類型屬性"+fldd.length);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
           

3、方法

步驟為:通過反射機制得到某個類的某個方法,然後調用對應于這個類的某個執行個體的該方法

package com.test.reflect;

import java.lang.reflect.Method;

public class MethodDemo {
    public int add(int a, int b){  
        return a + b;  
    }  
	public static void main(String args[]) {

		try {
			Class cls = Class.forName("com.test.reflect.MethodDemo");
			Class partypes[] = new Class[2];
			partypes[0] = Integer.TYPE;
			partypes[1] = Integer.TYPE;

			Method meth = cls.getMethod("add", partypes);
			MethodDemo methobj = new MethodDemo();

			Object arglist[] = new Object[2];
			arglist[0] = new Integer(37);
			arglist[1] = new Integer(47);

			Object retobj = meth.invoke(methobj, arglist);
			Integer retval = (Integer) retobj;
			System.out.println(retval.intValue());
		} catch (Throwable e) {
			System.err.println(e);
		}
	}
}