1. 程式人生 > >Java反射機制深入研究

Java反射機制深入研究

Java反射是Java語言的一個很重要的特徵,它使得Java具體了“動態性”。

在Java執行時環境中,對於任意一個類,能否知道這個類有哪些屬性和方法?對於任意一個物件,能否呼叫它的任意一個方法?答案是肯定的。這種動態獲取類的資訊以及動態呼叫物件的方法的功能來自於Java語言的反射(Reflection)機制。


Java反射機制主要提供了以下功能:
在執行時判斷任意一個物件所屬的類。
在執行時構造任意一個類的物件。
在執行時判斷任意一個類所具有的成員變數和方法。
在執行時呼叫任意一個物件的方法。

Reflection是Java被視為動態(或準動態)語言的一個關鍵性質。這個機制允許程式在執行時透過Reflection APIs取得任何一個已知名稱的class的內部資訊,包括其modifiers(諸如public, static 等等)、superclass(例如Object)、實現之interfaces(例如Serializable),也包括fields和methods的所有資訊,並可於執行時改變fields內容或調methods。

一般而言,開發者社群說到動態語言,大致認同的一個定義是:“程式執行時,允許改變程式結構或變數型別,這種語言稱為動態語言”。從這個觀點看,Perl,Python,Ruby是動態語言,C++,Java,C#不是動態語言。

儘管在這樣的定義與分類下Java不是動態語言,它卻有著一個非常突出的動態相關機制:Reflection。這個字的意思是“反射、映象、倒影”,用在Java身上指的是我們可以於執行時載入、探知、使用編譯期間完全未知的classes。換句話說,Java程式可以載入一個執行時才得知名稱的class,獲悉其完整構造(但不包括methods定義),並生成其物件實體、或對其fields設值、或喚起其methods。這種“看透class”的能力(the ability of the program to examine itself)被稱為introspection(內省、內觀、反省)。Reflection和introspection是常被並提的兩個術語。

在JDK中,主要由以下類來實現Java反射機制,這些類都位於java.lang.reflect包中:
Class類:代表一個類。
Field 類:代表類的成員變數(成員變數也稱為類的屬性)。
Method類:代表類的方法。
Constructor 類:代表類的構造方法。
Array類:提供了動態建立陣列,以及訪問陣列的元素的靜態方法。

下面給出幾個例子看看Reflection API的實際運用:

一、通過Class類獲取成員變數、成員方法、介面、超類、構造方法等
 
在java.lang.Object 類中定義了getClass()方法,因此對於任意一個Java物件,都可以通過此方法獲得物件的型別。Class類是Reflection API 中的核心類,它有以下方法
getName():獲得類的完整名字。
getFields():獲得類的public型別的屬性。
getDeclaredFields():獲得類的所有屬性。
getMethods():獲得類的public型別的方法。
getDeclaredMethods():獲得類的所有方法。
getMethod(String name, Class[] parameterTypes):獲得類的特定方法,name引數指定方法的名字,parameterTypes 引數指定方法的引數型別。
getConstructors():獲得類的public型別的構造方法。
getConstructor(Class[] parameterTypes):獲得類的特定構造方法,parameterTypes 引數指定構造方法的引數型別。
newInstance():通過類的不帶引數的構造方法建立這個類的一個物件。

Class<? super T> getSuperclass():返回本類的父類
Type getGenericSuperclass():返回本類的父類,包含泛型引數資訊
Type[] getGenericInterfaces():以Type的形式返回本類直接實現的介面,這樣就包含了泛型引數資訊
Class[] getInterfaces():返回本類直接實現的介面.不包含泛型引數資訊

下面給出一個綜合運用的例子:

複製程式碼 package com.ljq.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;

publicclass RefConstructor {

publicstaticvoid main(String[] args) throws Exception {
RefConstructor ref 
=new RefConstructor();
ref.getConstructor();
}

publicvoid getConstructor() throws Exception {
Class c 
=null;
= Class.forName("java.lang.Long");
Class cs[] 
= { java.lang.String.class };

System.out.println(
"\n--------------構造器的使用-----------------\n");
Constructor cst1 
= c.getConstructor(cs);
System.out.println(
"1、通過引數獲取指定Class物件的構造方法:");
System.out.println(cst1.toString());

Constructor cst2 
= c.getDeclaredConstructor(cs);
System.out.println(
"2、通過引數獲取指定Class物件所表示的類或介面的構造方法:");
System.out.println(cst2.toString());

Constructor cst3 
= c.getEnclosingConstructor();
System.out.println(
"3、獲取本地或匿名類Constructor物件,它表示基礎類的立即封閉構造方法。");
if (cst3 !=null) System.out.println(cst3.toString());
else System.out.println("沒有獲取到任何構造方法!");

//Constructor[] csts = c.getDeclaredConstructors(); //獲取所有的構造器Constructor[] csts = c.getConstructors(); //獲取public型別的構造器System.out.println("4、獲取指定Class物件的所有構造方法:");
for (int i =0; i < csts.length; i++) {
System.out.println(csts[i].toString());
}

System.out.println(
"\n--------------型別的使用-----------------\n");
Type types1[] 
= c.getGenericInterfaces(); //獲取實現的介面System.out.println("1、返回直接實現的介面:");
for (int i =0; i < types1.length; i++) {
System.out.println(types1[i].toString());
}

Type type1 
= c.getGenericSuperclass(); ////獲取父類System.out.println("2、返回直接超類:");
System.out.println(type1.toString());

Class[] cis 
= c.getClasses();
System.out.println(
"3、返回超類和所有實現的介面:");
System.out.println(
"length="+cis.length);
for (int i =0; i < cis.length; i++) {
System.out.println(cis[i].toString());
}

Class cs1[] 
= c.getInterfaces();
System.out.println(
"4、實現的介面");
for (int i =0; i < cs1.length; i++) {
System.out.println(cs1[i].toString());
}

System.out.println(
"5、父類");
System.out.println(c.getSuperclass());

System.out.println(
"\n--------------成員變數的使用-----------------\n");
Field fs1[] 
= c.getFields(); //獲取PUBLIC型別的屬性System.out.println("1、類或介面的所有可訪問公共欄位:");
for (int i =0; i < fs1.length; i++) {
System.out.println(fs1[i].toString());
}

Field f1 
= c.getField("MIN_VALUE"); //獲取指定的屬性System.out.println("2、類或介面的指定已宣告指定公共成員欄位:");
System.out.println(f1.toString());

Field fs2[] 
= c.getDeclaredFields(); //獲取所有的屬性System.out.println("3、類或介面所宣告的所有欄位:");
for (int i =0; i < fs2.length; i++) {
System.out.println(fs2[i].toString());
}

Field f2 
= c.getDeclaredField("serialVersionUID");
System.out.println(
"4、類或介面的指定已宣告指定欄位:");
System.out.println(f2.toString());

System.out.println(
"\n--------------成員方法的使用-----------------\n");
//Method m1[] = c.getDeclaredMethods();Method m1[] = c.getMethods();
System.out.println(
"1、返回類所有的公共成員方法:");
for (int i =0; i < m1.length; i++) {
System.out.println(m1[i].toString());
}

//Method m2 = c.getDeclaredMethod("longValue", new Class[]{});Method m2 = c.getMethod("longValue"new Class[]{});
System.out.println(
"2、返回指定公共成員方法:");
System.out.println(m2.toString());
}
}
複製程式碼

執行結果為:

複製程式碼 --------------構造器的使用-----------------1、通過引數獲取指定Class物件的構造方法:
public java.lang.Long(java.lang.String) throws java.lang.NumberFormatException
2、通過引數獲取指定Class物件所表示的類或介面的構造方法:
public java.lang.Long(java.lang.String) throws java.lang.NumberFormatException
3、獲取本地或匿名類Constructor物件,它表示基礎類的立即封閉構造方法。
沒有獲取到任何構造方法!
4、獲取指定Class物件的所有構造方法:
public java.lang.Long(java.lang.String) throws java.lang.NumberFormatException
public java.lang.Long(long)

--------------型別的使用-----------------1、返回直接實現的介面:
java.lang.Comparable
<java.lang.Long>2、返回直接超類:
class java.lang.Number
3、返回超類和所有實現的介面:
length
=04、實現的介面
interface java.lang.Comparable
5、父類
class java.lang.Number

--------------成員變數的使用-----------------1、類或介面的所有可訪問公共欄位:
publicstaticfinallong java.lang.Long.MIN_VALUE
publicstaticfinallong java.lang.Long.MAX_VALUE
publicstaticfinal java.lang.Class java.lang.Long.TYPE
publicstaticfinalint java.lang.Long.SIZE
2、類或介面的指定已宣告指定公共成員欄位:
publicstaticfinallong java.lang.Long.MIN_VALUE
3、類或介面所宣告的所有欄位:
publicstaticfinallong java.lang.Long.MIN_VALUE
publicstaticfinallong java.lang.Long.MAX_VALUE
publicstaticfinal java.lang.Class java.lang.Long.TYPE
privatefinallong java.lang.Long.value
publicstaticfinalint java.lang.Long.SIZE
privatestaticfinallong java.lang.Long.serialVersionUID
4、類或介面的指定已宣告指定欄位:
privatestaticfinallong java.lang.Long.serialVersionUID

--------------成員方法的使用-----------------1、返回類所有的公共成員方法:
publicint java.lang.Long.hashCode()
publicstaticlong java.lang.Long.reverseBytes(long)
publicint java.lang.Long.compareTo(java.lang.Object)
publicint java.lang.Long.compareTo(java.lang.Long)
publicstatic java.lang.Long java.lang.Long.getLong(java.lang.String)
publicstatic java.lang.Long java.lang.Long.getLong(java.lang.String,long)
publicstatic java.lang.Long java.lang.Long.getLong(java.lang.String,java.lang.Long)
publicboolean java.lang.Long.equals(java.lang.Object)
publicstatic java.lang.String java.lang.Long.toString(long)
publicstatic java.lang.String java.lang.Long.toString(long,int)
public java.lang.String java.lang.Long.toString()
publicstatic java.lang.String java.lang.Long.toHexString(long)
publicstatic java.lang.Long java.lang.Long.decode(java.lang.String) throws java.lang.NumberFormatException
publicstatic java.lang.Long java.lang.Long.valueOf(java.lang.String) throws java.lang.NumberFormatException
publicstatic java.lang.Long java.lang.Long.valueOf(long)
publicstatic java.lang.Long java.lang.Long.valueOf(java.lang.String,intthrows java.lang.NumberFormatException
publicstaticlong java.lang.Long.reverse(long)
publicbyte java.lang.Long.byteValue()
publicdouble java.lang.Long.doubleValue()
publicfloat java.lang.Long.floatValue()
publicint java.lang.Long.intValue()
publiclong java.lang.Long.longValue()
publicshort java.lang.Long.shortValue()
publicstaticint java.lang.Long.bitCount(long)
publicstaticlong java.lang.Long.highestOneBit(long)
publicstaticlong java.lang.Long.lowestOneBit(long)
publicstaticint java.lang.Long.numberOfLeadingZeros(long)
publicstaticint java.lang.Long.numberOfTrailingZeros(long)
publicstaticlong java.lang.Long.rotateLeft(long,int)
publicstaticlong java.lang.Long.rotateRight(long,int)
publicstaticint java.lang.Long.signum(long)
publicstatic java.lang.String java.lang.Long.toBinaryString(long)
publicstatic java.lang.String java.lang.Long.toOctalString(long)
publicstaticlong java.lang.Long.parseLong(java.lang.String,intthrows java.lang.NumberFormatException
publicstaticlong java.lang.Long.parseLong(java.lang.String) throws java.lang.NumberFormatException
publicfinalvoid java.lang.Object.wait() throws java.lang.InterruptedException
publicfinalvoid java.lang.Object.wait(long,intthrows java.lang.InterruptedException
publicfinalnativevoid java.lang.Object.wait(longthrows java.lang.InterruptedException
publicfinalnative java.lang.Class java.lang.Object.getClass()
publicfinalnativevoid java.lang.Object.notify()
publicfinalnativevoid java.lang.Object.notifyAll()
2、返回指定公共成員方法:
publiclong java.lang.Long.longValue() 複製程式碼

二、執行時複製物件

例程ReflectTester 類進一步演示了Reflection API的基本使用方法。ReflectTester類有一個copy(Object object)方法,這個方法能夠建立一個和引數object 同樣型別的物件,然後把object物件中的所有屬性拷貝到新建的物件中,並將它返回。這個例子只能複製簡單的JavaBean,假定JavaBean 的每個屬性都有public 型別的getXXX()和setXXX()方法。

複製程式碼 package com.ljq.test;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 模擬執行時複製物件

@author jiqinlin
*
*/publicclass ReflectTester {
public Object copy(Object object) throws Exception {
// 獲得物件的型別Class<?> classType = object.getClass();
System.out.println(
"Class:"+ classType.getName());

// 通過預設構造方法建立一個新的物件Object objectCopy = classType.getConstructor(new Class[] {}).newInstance(new Object[] {});

// 獲得物件的所有屬性Field fields[] = classType.getDeclaredFields();

for (int i =0; i < fields.length; i++) {
Field field 
= fields[i];

String fieldName 
= field.getName();
String firstLetter 
= fieldName.substring(01).toUpperCase();
// 獲得和屬性對應的getXXX()方法的名字String getMethodName ="get"+ firstLetter + fieldName.substring(1);
// 獲得和屬性對應的setXXX()方法的名字String setMethodName ="set"+ firstLetter + fieldName.substring(1);

// 獲得和屬性對應的getXXX()方法Method getMethod = classType.getMethod(getMethodName,new Class[] {});
// 獲得和屬性對應的setXXX()方法Method setMethod = classType.getMethod(setMethodName,new Class[] { field.getType() });

// 呼叫原物件的getXXX()方法Object value = getMethod.invoke(object, new Object[] {});
System.out.println(fieldName 
+":"+ value);
// 呼叫拷貝物件的setXXX()方法setMethod.invoke(objectCopy, new Object[] { value });
}
return objectCopy;
}

publicstaticvoid main(String[] args) throws Exception {
Customer customer 
=new Customer("Tom"21);
customer.setId(
new Long(1));

Customer customerCopy 
= (Customer) new ReflectTester().copy(customer);
System.out.println(
"Copy information:"+ customerCopy.getId() +""+ 
customerCopy.getName() 
+""+ customerCopy.getAge());
}

}
複製程式碼 複製程式碼 package com.ljq.test;

publicclass Customer {
private Long id;
private String name;
privateint age;

public Customer() {
}

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

public Long getId() {
return id;
}

publicvoid setId(Long id) {