① java中反射的三種方法是
第一種:通過forName()方法;
第二種:類.class;
第三種:對象.getClass()。
舉例如下:
package
test;
public class Demo{
public static void
main(){
Class<?> c1 = null;
Class<?> c2 =
null;
Class<?> c3 =
null;
//三種反射用實例化方式
try{
//最常用的一種形式
c1 =
Class.forName("test.X");
}catch(ClassNotFoundException
e){
e.printStackTrace();
}
//通過Object類中的方法實例化
c2
= new X().getClass();
//通過類.class實例化
c3 =
X.class;
System.out.println("類名:" + c1.getName());
//得到類名
System.out.println("類名:" + c2.getName());
//得到類名
System.out.println("類名:" + c3.getName());
//得到類名
}
}
② java反射機制詳解
反射就是把Java的各種成分映射成相應的Java類。
Class類的構造方法是private,由JVM創建。
反射是java語言的一個特性,它允程序在運行時(注意不是編譯的時候)來進行自我檢查並且對內部的成員進行操作。例如它允許一個java的類獲取他所有的成員變數和方法並且顯示出來。Java 的這一能力在實際應用中也許用得不是很多,但是在其它的程序設計語言中根本就不存在這一特性。例如,Pascal、C 或者 C++ 中就沒有辦法在程序中獲得函數定義相關的信息。(來自Sun)
JavaBean 是 reflection 的實際應用之一,它能讓一些工具可視化的操作軟體組件。這些工具通過 reflection 動態的載入並取得 Java 組件(類) 的屬性。
反射是從1.2就有的,後面的三大框架都會用到反射機制,涉及到類"Class",無法直接new CLass(),其對象是內存里的一份位元組碼.
Class 類的實例表示正在運行的 Java 應用程序中的類和介面。枚舉是一種類,注釋是一種介面。每個數組屬於被映射為 Class 對象的一個類,所有具有相同元素類型和維數的數組都共享該 Class 對象。
基本的 Java類型(boolean、byte、char、short、int、long、float 和 double)和關鍵字 void 也表示為 Class 對象。Class 沒有公共構造方法。
Class 對象是在載入類時由 Java 虛擬機以及通過調用類載入器中的 defineClass 方法自動構造的。
Person p1 = new Person();
//下面的這三種方式都可以得到位元組碼
CLass c1 = Date.class();
p1.getClass();
//若存在則載入,否則新建,往往使用第三種,類的名字在寫源程序時不需要知道,到運行時再傳遞過來
Class.forName("java.lang.String");
Class.forName()位元組碼已經載入到java虛擬機中,去得到位元組碼;java虛擬機中還沒有生成位元組碼 用類載入器進行載入,載入的位元組碼緩沖到虛擬機中。
另外,大家可以關注微信公眾號Java技術棧回復:JVM,獲取我整理的系列JVM教程,都是干貨。
考慮下面這個簡單的例子,讓我們看看 reflection 是如何工作的。
import java.lang.reflect.*;
public class DumpMethods {
public static void main(String args[]) {
try {
Class c = Class.forName("java.util.Stack");
Method m[] = c.getDeclaredMethods();
for (int i = 0; i < m.length; i++)
System.out.println(m[i].toString());
}
catch (Throwable e){
System.err.println(e);
}
}
}
public synchronized java.lang.Object java.util.Stack.pop()
public java.lang.Object java.util.Stack.push(java.lang.Object)
public boolean java.util.Stack.empty()
public synchronized java.lang.Object java.util.Stack.peek()
public synchronized int java.util.Stack.search(java.lang.Object)
這樣就列出了java.util.Stack 類的各方法名以及它們的限制符和返回類型。這個程序使用 Class.forName 載入指定的類,然後調用 getDeclaredMethods 來獲取這個類中定義了的方法列表。java.lang.reflect.Methods 是用來描述某個類中單個方法的一個類。
以下示例使用 Class 對象來顯示對象的類名:
void printClassName(Object obj) {
System.out.println("The class of " + obj +
" is " + obj.getClass().getName());
}
還可以使用一個類字面值(JLS Section 15.8.2)來獲取指定類型(或 void)的 Class 對象。例如:
System.out.println("The name of class Foo is: "+Foo.class.getName());
在沒有對象實例的時候,主要有兩種辦法。
//獲得類類型的兩種方式
Class cls1 = Role.class;
Class cls2 = Class.forName("yui.Role");
注意第二種方式中,forName中的參數一定是完整的類名(包名+類名),並且這個方法需要捕獲異常。現在得到cls1就可以創建一個Role類的實例了,利用Class的newInstance方法相當於調用類的默認的構造器。
Object o = cls1.newInstance();
//創建一個實例
//Object o1 = new Role(); //與上面的方法等價
③ Java 中Class.forName()動態調用類中靜態方法的問題
你可以使用Class.getMethod()方法,然後使用Method.invoke()進行方法調用
④ JAVA反射機製作用
一、什麼是反射:
反射的概念是由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 {
//載入指定的Java類
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);
//調用指定的方法並獲取返回值為Object類型
retobj= meth.invoke(obj, arglist);
}
catch (Throwable e) {
System.err.println(e);
}
return retobj;
}
//獲取參數類型Class[]的方法
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;
}
//獲取參數Object[]的方法
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 等都不具備的。但反射有兩個缺點。第一個是性能問題。用於欄位和方法接入時反射要遠慢於直接代碼。性能問題的程度取決於程序中是如何使用反射的。如果它作為程序運行中相對很少涉及的部分,緩慢的性能將不會是一個問題。即使測試中最壞情況下的計時圖顯示的反射操作只耗用幾微秒。僅反射在性能關鍵的應用的核心邏輯中使用時性能問題才變得至關重要。
⑤ JAVA中反射是什麼
JAVA中反射是動態獲取信息以及動態調用對象方法的一種反射機制。
Java反射就是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意方法和屬性;並且能改變它的屬性。而這也是Java被視為動態語言的一個關鍵性質。
Java反射的功能是在運行時判斷任意一個對象所屬的類,在運行時構造任意一個類的對象,在運行時判斷任意一個類所具有的成員變數和方法,在運行時調用任意一個對象的方法,生成動態代理。
(5)java反射靜態方法調用靜態方法擴展閱讀:
JAVA中反射實例:
1、Class superClass=clazz.getSuperclass();//獲取父類。
System.out.println("getSuperclass:"+superClass)。
2、Class[] interfaces=clazz.getInterfaces();//獲取實現介面。
System.out.println("getInterfaces:"+interfaces.length)。
3、Constructor[] cons=clazz.getConstructors();//構造方法。
System.out.println("getConstructors:"+cons.length)。
參考資料來源:網路: JAVA反射機制
⑥ 關於用java反射調用一個類裡面的方法並執行
Java中要用到反射,首先就必須要獲取到對應的class對象,在Java中有三種方法獲取類對應的class對象。
1、通過類的.class屬性
2、通過類實例的getClass()方法獲取
3、通過Class.forName(String className)方法獲取
現在比如在package下有個類Calculator
publicclassCalculator{
publicdoubleadd(doublescore1,doublescore2){
returnscore1+score2;
}
publicvoidprint(){
System.out.println("OK");
}
publicstaticdoublemul(doublescore1,doublescore2){
returnscore1*score2;
}
}
publicclassCalculatorTest{
publicstaticvoidmain(String[]args)throwsException{
//通過類的.class屬性獲取
Class<Calculator>clz=Calculator.class;
//或者通過類的完整路徑獲取,這個方法由於不能確定傳入的路徑是否正確,這個方法會拋ClassNotFoundException
// Class<Calculator>clz=Class.forName("test.Calculator");
//或者new一個實例,然後通過實例的getClass()方法獲取
// Calculators=newCalculator();
// Class<Calculator>clz=s.getClass();
//1.獲取類中帶有方法簽名的mul方法,getMethod第一個參數為方法名,第二個參數為mul的參數類型數組
Methodmethod=clz.getMethod("mul",newClass[]{double.class,double.class});
//invoke方法的第一個參數是被調用的對象,這里是靜態方法故為null,第二個參數為給將被調用的方法傳入的參數
Objectresult=method.invoke(null,newObject[]{2.0,2.5});
//如果方法mul是私有的private方法,按照上面的方法去調用則會產生異常NoSuchMethodException,這時必須改變其訪問屬性
//method.setAccessible(true);//私有的方法通過發射可以修改其訪問許可權
System.out.println(result);//結果為5.0
//2.獲取類中的非靜態方法
Methodmethod_2=clz.getMethod("add",newClass[]{double.class,double.class});
//這是實例方法必須在一個對象上執行
Objectresult_2=method_2.invoke(newCalculator(),newObject[]{2.0,2.5});
System.out.println(result_2);//4.5
//3.獲取沒有方法簽名的方法print
Methodmethod_3=clz.getMethod("print",newClass[]{});
Objectresult_3=method_3.invoke(newCalculator(),null);//result_3為null,該方法不返回結果
}
}
⑦ Java Reflection (JAVA反射)機制詳解
反射機制:所謂的反射機制就是java語言在運行時擁有一項自觀的能力。通過這種能力可以徹底的了解自身的情況為下一步的動作做准備。下面具體介紹一下java的反射機制。這里你將顛覆原來對java的理解。
Java的反射機制的實現要藉助於4個類:class,Constructor,Field,Method;其中class代表的時類對 象,Constructor-類的構造器對象,Field-類的屬性對象,Method-類的方法對象。通過這四個對象我們可以粗略的看到一個類的各個組 成部分。
Class:程序運行時,java運行時系統會對所有的對象進行運行時類型的處理。這項信息記錄了每個對象所屬的類,虛擬機通常使用運行時類型信息選擇正 確的方法來執行(摘自:白皮書)。但是這些信息我們怎麼得到啊,就要藉助於class類對象了啊。在Object類中定義了getClass()方法。我 們可以通過這個方法獲得指定對象的類對象。然後我們通過分析這個對象就可以得到我們要的信息了。
比如:ArrayList arrayList;
Class clazz = arrayList.getClass();
然後我來處理這個對象clazz。
當然了Class類具有很多的方法,這里重點將和Constructor,Field,Method類有關系的方法。
Reflection 是 Java 程序開發語言的特徵之一,它允許運行中的 Java 程序對自身進行檢查,或者說「自審」,並能直接操作程序的內部屬性。Java 的這一能力在實際應用中也許用得不是很多,但是個人認為要想對java有個更加深入的了解還是應該掌握的。
1.檢測類:
reflection的工作機制
考慮下面這個簡單的例子,讓我們看看 reflection 是如何工作的。
import java.lang.reflect.*;
public class DumpMethods {
public static void main(String args[]) {
try {
Class c = Class.forName(args[0]);
Method m[] = c.getDeclaredMethods();
for (int i = 0; i < m.length; i++)
System.out.println(m[i].toString());
} catch (Throwable e) {
System.err.println(e);
}
}
}
按如下語句執行:
java DumpMethods java.util.ArrayList
這個程序使用 Class.forName 載入指定的類,然後調用 getDeclaredMethods 來獲取這個類中定義了的方法列表。java.lang.reflect.Methods 是用來描述某個類中單個方法的一個類。
Java類反射中的主要方法
對於以下三類組件中的任何一類來說 -- 構造函數、欄位和方法 -- java.lang.Class 提供四種獨立的反射調用,以不同的方式來獲得信息。調用都遵循一種標准格式。以下是用於查找構造函數的一組反射調用:
Constructor getConstructor(Class[] params) -- 獲得使用特殊的參數類型的公共構造函數,
Constructor[] getConstructors() -- 獲得類的所有公共構造函數
Constructor getDeclaredConstructor(Class[] params) -- 獲得使用特定參數類型的構造函數(與接入級別無關)
Constructor[] getDeclaredConstructors() -- 獲得類的所有構造函數(與接入級別無關)
獲得欄位信息的Class 反射調用不同於那些用於接入構造函數的調用,在參數類型數組中使用了欄位名:
Field getField(String name) -- 獲得命名的公共欄位
Field[] getFields() -- 獲得類的所有公共欄位
Field getDeclaredField(String name) -- 獲得類聲明的命名的欄位
Field[] getDeclaredFields() -- 獲得類聲明的所有欄位
用於獲得方法信息函數:
Method getMethod(String name, Class[] params) -- 使用特定的參數類型,獲得命名的公共方法
Method[] getMethods() -- 獲得類的所有公共方法
Method getDeclaredMethod(String name, Class[] params) -- 使用特寫的參數類型,獲得類聲明的命名的方法
Method[] getDeclaredMethods() -- 獲得類聲明的所有方法
使用 Reflection:
用於 reflection 的類,如 Method,可以在 java.lang.relfect 包中找到。使用這些類的時候必須要遵循三個步驟:第一步是獲得你想操作的類的 java.lang.Class 對象。在運行中的 Java 程序中,用 java.lang.Class 類來描述類和介面等。
下面就是獲得一個 Class 對象的方法之一:
Class c = Class.forName("java.lang.String");
這條語句得到一個 String 類的類對象。還有另一種方法,如下面的語句:
Class c = int.class;
或者
Class c = Integer.TYPE;
它們可獲得基本類型的類信息。其中後一種方法中訪問的是基本類型的封裝類 (如 Intege ) 中預先定義好的 TYPE 欄位。
第二步是調用諸如 getDeclaredMethods 的方法,以取得該類中定義的所有方法的列表。
一旦取得這個信息,就可以進行第三步了——使用 reflection API 來操作這些信息,如下面這段代碼:
Class c = Class.forName("java.lang.String");
Method m[] = c.getDeclaredMethods();
System.out.println(m[0].toString());
它將以文本方式列印出 String 中定義的第一個方法的原型。
處理對象:
a.創建一個Class對象
b.通過getField 創建一個Field對象
c.調用Field.getXXX(Object)方法(XXX是Int,Float等,如果是對象就省略;Object是指實例).
例如:
import java.lang.reflect.*;
import java.awt.*;
class SampleGet {
public static void main(String[] args) {
Rectangle r = new Rectangle(100, 325);
printHeight(r);
}
static void printHeight(Rectangle r) {
Field heightField;
Integer heightValue;
Class c = r.getClass();
try {
heightField = c.getField("height");
heightValue = (Integer) heightField.get(r);
System.out.println("Height: " + heightValue.toString());
} catch (NoSuchFieldException e) {
System.out.println(e);
} catch (SecurityException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
}
}
}
安全性和反射:
在處理反射時安全性是一個較復雜的問題。反射經常由框架型代碼使用,由於這一點,我們可能希望框架能夠全面接入代碼,無需考慮常規的接入限制。但是,在其它情況下,不受控制的接入會帶來嚴重的安全性風險,例如當代碼在不值得信任的代碼共享的環境中運行時。
由於這些互相矛盾的需求,Java編程語言定義一種多級別方法來處理反射的安全性。基本模式是對反射實施與應用於源代碼接入相同的限制:
從任意位置到類公共組件的接入
類自身外部無任何到私有組件的接入
受保護和打包(預設接入)組件的有限接入
不過至少有些時候,圍繞這些限制還有一種簡單的方法。我們可以在我們所寫的類中,擴展一個普通的基本類 java.lang.reflect.AccessibleObject 類。這個類定義了一種setAccessible方法,使我們能夠啟動或關閉對這些類中其中一個類的實例的接入檢測。唯一的問題在於如果使用了安全性管理 器,它將檢測正在關閉接入檢測的代碼是否許可了這樣做。如果未許可,安全性管理器拋出一個例外。
下面是一段程序,在TwoString 類的一個實例上使用反射來顯示安全性正在運行:
public class ReflectSecurity {
public static void main(String[] args) {
try {
TwoString ts = new TwoString("a", "b");
Field field = clas.getDeclaredField("m_s1");
// field.setAccessible(true);
System.out.println("Retrieved value is " +
field.get(inst));
} catch (Exception ex) {
ex.printStackTrace(System.out);
}
}
}
如果我們編譯這一程序時,不使用任何特定參數直接從命令行運行,它將在field .get(inst)調用中拋出一個IllegalAccessException異常。如果我們不注釋 field.setAccessible(true)代碼行,那麼重新編譯並重新運行該代碼,它將編譯成功。最後,如果我們在命令行添加了JVM參數 -Djava.security.manager以實現安全性管理器,它仍然將不能通過編譯,除非我們定義了ReflectSecurity類的許可權 限。
反射性能:(轉錄別人的啊)
反射是一種強大的工具,但也存在一些不足。一個主要的缺點是對性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什麼並且它滿足我們的要求。這類操作總是慢於只直接執行相同的操作。
下面的程序是欄位接入性能測試的一個例子,包括基本的測試方法。每種方法測試欄位接入的一種形式 -- accessSame 與同一對象的成員欄位協作,accessOther 使用可直接接入的另一對象的欄位,accessReflection 使用可通過反射接入的另一對象的欄位。在每種情況下,方法執行相同的計算 -- 循環中簡單的加/乘順序。
程序如下:
public int accessSame(int loops) {
m_value = 0;
for (int index = 0; index < loops; index++) {
m_value = (m_value + ADDITIVE_VALUE) *
MULTIPLIER_VALUE;
}
return m_value;
}
public int acces
sReference(int loops) {
TimingClass timing = new TimingClass();
for (int index = 0; index < loops; index++) {
timing.m_value = (timing.m_value + ADDITIVE_VALUE) *
MULTIPLIER_VALUE;
}
return timing.m_value;
}
public int accessReflection(int loops) throws Exception {
TimingClass timing = new TimingClass();
try {
Field field = TimingClass.class.
getDeclaredField("m_value");
for (int index = 0; index < loops; index++) {
int value = (field.getInt(timing) +
ADDITIVE_VALUE) * MULTIPLIER_VALUE;
field.setInt(timing, value);
}
return timing.m_value;
} catch (Exception ex) {
System.out.println("Error using reflection");
throw ex;
}
}
在上面的例子中,測試程序重復調用每種方法,使用一個大循環數,從而平均多次調用的時間衡量結果。平均值中不包括每種方法第一次調用的時間,因此初始化時間不是結果中的一個因素。下面的圖清楚的向我們展示了每種方法欄位接入的時間:
圖 1:欄位接入時間 :
我們可以看出:在前兩副圖中(Sun JVM),使用反射的執行時間超過使用直接接入的1000倍以上。通過比較,IBM JVM可能稍好一些,但反射方法仍舊需要比其它方法長700倍以上的時間。任何JVM上其它兩種方法之間時間方面無任何顯著差異,但IBM JVM幾乎比Sun JVM快一倍。最有可能的是這種差異反映了Sun Hot Spot JVM的專業優化,它在簡單基準方面表現得很糟糕。反射性能是Sun開發1.4 JVM時關注的一個方面,它在反射方法調用結果中顯示。在這類操作的性能方面,Sun 1.4.1 JVM顯示了比1.3.1版本很大的改進。
如果為為創建使用反射的對象編寫了類似的計時測試程序,我們會發現這種情況下的差異不象欄位和方法調用情況下那麼顯著。使用newInstance()調 用創建一個簡單的java.lang.Object實例耗用的時間大約是在Sun 1.3.1 JVM上使用new Object()的12倍,是在IBM 1.4.0 JVM的四倍,只是Sun 1.4.1 JVM上的兩部。使用Array.newInstance(type, size)創建一個數組耗用的時間是任何測試的JVM上使用new type[size]的兩倍,隨著數組大小的增加,差異逐步縮小。隨著jdk6.0的推出,反射機制的性能也有了很大的提升。期待中….
總結:
Java語言反射提供一種動態鏈接程序組件的多功能方法。它允許程序創建和控制任何類的對象(根據安全性限制),無需提前硬編碼目標類。這些特性使得反射 特別適用於創建以非常普通的方式與對象協作的庫。例如,反射經常在持續存儲對象為資料庫、XML或其它外部格式的框架中使用。Java reflection 非常有用,它使類和數據結構能按名稱動態檢索相關信息,並允許在運行著的程序中操作這些信息。Java 的這一特性非常強大,並且是其它一些常用語言,如 C、C++、Fortran 或者 Pascal 等都不具備的。
但反射有兩個缺點。第一個是性能問題。用於欄位和方法接入時反射要遠慢於直接代碼。性能問題的程度取決於程序中是如何使用反射的。如果它作為程序運行中相 對很少涉及的部分,緩慢的性能將不會是一個問題。即使測試中最壞情況下的計時圖顯示的反射操作只耗用幾微秒。僅反射在性能關鍵的應用的核心邏輯中使用時性 能問題才變得至關重要。
許多應用中更嚴重的一個缺點是使用反射會模糊程序內部實際要發生的事情。程序人員希望在源代碼中看到程序的邏輯,反射等繞過了源代碼的技術會帶來維護問 題。反射代碼比相應的直接代碼更復雜,正如性能比較的代碼實例中看到的一樣。解決這些問題的最佳方案是保守地使用反射——僅在它可以真正增加靈活性的地方 ——記錄其在目標類中的使用。
一下是對應各個部分的例子:
具體的應用:
1、 模仿instanceof 運算符號
class A {}
public class instance1 {
public static void main(String args[])
{
try {
Class cls = Class.forName("A");
boolean b1
= cls.isInstance(new Integer(37));
System.out.println(b1);
boolean b2 = cls.isInstance(new A());
System.out.println(b2);
}
catch (Throwable e) {
System.err.println(e);
}
}
}
2、 在類中尋找指定的方法,同時獲取該方法的參數列表,例外和返回值
import java.lang.reflect.*;
public class method1 {
private int f1(
Object p, int x) throws NullPointerException
{
if (p == null)
throw new NullPointerException();
return x;
}
public static void main(String args[])
{
try {
Class cls = Class.forName("method1");
Method methlist[]
= cls.getDeclaredMethods();
for (int i = 0; i < methlist.length;
i++)
Method m = methlist[i];
System.out.println("name
= " + m.getName());
System.out.println("decl class = " +
m.getDeclaringClass());
Class pvec[] = m.getParameterTypes();
for (int j = 0; j < pvec.length; j++)
System.out.println("
param #" + j + " " + pvec[j]);
Class evec[] = m.getExceptionTypes();
for (int j = 0; j < evec.length; j++)
System.out.println("exc #" + j
+ " " + evec[j]);
System.out.println("return type = " +
m.getReturnType());
System.out.println("-----");
}
}
catch (Throwable e) {
System.err.println(e);
}
}
}
3、 獲取類的構造函數信息,基本上與獲取方法的方式相同
import java.lang.reflect.*;
public class constructor1 {
public constructor1()
{
}
protected constructor1(int i, double d)
{
}
public static void main(String args[])
{
try {
Class cls = Class.forName("constructor1");
Constructor ctorlist[]
= cls.getDeclaredConstructors();
for (int i = 0; i < ctorlist.length; i++) {
Constructor ct = ctorlist[i];
System.out.println("name
= " + ct.getName());
System.out.println("decl class = " +
ct.getDeclaringClass());
Class pvec[] = ct.getParameterTypes();
for (int j = 0; j < pvec.length; j++)
System.out.println("param #"
+ j + " " + pvec[j]);
Class evec[] = ct.getExceptionTypes();
for (int j = 0; j < evec.length; j++)
System.out.println(
"exc #" + j + " " + evec[j]);
System.out.println("-----");
}
}
catch (Throwable e) {
System.err.println(e);
}
}
}
4、 獲取類中的各個數據成員對象,包括名稱。類型和訪問修飾符號
import java.lang.reflect.*;
public class field1 {
private double d;
public static final int i = 37;
String s = "testing";
public static void main(String args[])
{
try {
Class cls = Class.forName("field1");
Field fieldlist[]
= cls.getDeclaredFields();
for (int i
= 0; i < fieldlist.length; i++) {
Field fld = fieldlist[i];
System.out.println("name
= " + fld.getName());
System.out.println("decl class = " +
fld.getDeclaringClass());
System.out.println("type
= " + fld.getType());
int mod = fld.getModifiers();
System.out.println("modifiers = " +
Modifier.toString(mod));
System.out.println("-----");
}
}
catch (Throwable e) {
System.err.println(e);
}
}
}
5、 通過使用方法的名字調用方法
import java.lang.reflect.*;
public class method2 {
public int add(int a, int b)
{
return a + b;
}
public static void main(String args[])
{
try {
Class cls = Class.forName("method2");
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
Method meth = cls.getMethod(
"add", partypes);
method2 methobj = new method2();
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);
}
}
}
6、 創建新的對象
import java.lang.reflect.*;
public class constructor2 {
public constructor2()
{
}
public constructor2(int a, int b)
{
System.out.println(
"a = " + a + " b = " + b);
}
public static void main(String args[])
{
try {
Class cls = Class.forName("constructor2");
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
Constructor ct
= cls.getConstructor(partypes);
Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Integer(47);
Object retobj = ct.newInstance(arglist);
}
catch (Throwable e) {
System.err.println(e);
}
}
}
7、 變更類實例中的數據的值
import java.lang.reflect.*;
public class field2 {
public double d;
public static void main(String args[])
{
try {
Class cls = Class.forName("field2");
Field fld = cls.getField("d");
field2 f2obj = new field2();
System.out.println("d = " + f2obj.d);
fld.setDouble(f2obj, 12.34);
System.out.println("d = " + f2obj.d);
}
catch (Throwable e) {
System.err.println(e);
}
}
}
使用反射創建可重用代碼:
1、 對象工廠
Object factory(String p) {
Class c;
Object o=null;
try {
c = Class.forName(p);// get class def
o = c.newInstance(); // make a new one
} catch (Exception e) {
System.err.println("Can't make a " + p);
}
return o;
}
public class ObjectFoundry {
public static Object factory(String p)
throws ClassNotFoundException,
InstantiationException,
IllegalAccessException {
Class c = Class.forName(p);
Object o = c.newInstance();
return o;
}
}
2、 動態檢測對象的身份,替代instanceof
public static boolean
isKindOf(Object obj, String type)
throws ClassNotFoundException {
// get the class def for obj and type
Class c = obj.getClass();
Class tClass = Class.forName(type);
while ( c!=null ) {
if ( c==tClass ) return true;
c = c.getSuperclass();
}
return false;
}