定義一、能夠分析類能力的程式成為反射。(核心卷一定義) 定義二、 主要是指程式可以通路,檢測和修改它本身狀态或行為的一種能力,并能根據自身行為的狀态和結果,調整或修改應用所描述行為的狀态和相關的語義。(網上找的定義義)
反射機制可以用來: 在運作中分析類的能力。 在運作中檢視對象。 實作通用的數組操作代碼 利用Method對象,這個對象很想c++中的函數指針。 一、利用反射分析類的能力 1、反射機制最重要的内容——檢查類的結構 sun為我們提供了那些反射機制中的類:
java.lang.Class;
java.lang.reflect.Constructor; java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier; 在java.lang.reflect包中有三個類Field、Method、Constructor分别用于描述類的域、方法和構造器。這三個類都有一個叫做getName的方法,用于傳回項目的名稱。 Field類有一個getType方法,用來傳回描述域所屬類型的Class對象。Method和Constructor類有能夠報告參數類型的方法,Method類還有一個可以報告傳回類型的方法。這三個類還有一個叫做getModifiers的方法,它将傳回一個整型數值,用不同的位開關描述public和static這樣的修飾符使用狀況。 Class類中的getField,getMethod和getConstructors方法将分别傳回類提供的public域、方法和構造器數組,其中包括超累的公有成員。Class類的getDeclareField、getDeclareMethods和getDeclaredConstructors方法将分别傳回類中聲明的全部域、方法和構造器,其中包括私有和受保護成員,但不包括超累的成員。
一、Class類的使用

package com.slowly.reflectTest;
import java.lang.reflect.Method;
class MyFather {
public int fatherMember;
public void methodFather(){
System. out.println( "我是從父類繼承而來的方法methodFather" );
}
}
class Son extends MyFather{
public int sonMemberpublic;
@SuppressWarnings( "unused")
private int sonMemberprivate;
public void methodSon(){
System. out.println( "我是子類自己的方法!" );
}
protected void methodsonProtected(){
System. out.println( "我是子類受保護的方法!!" );
}
}
public class reflectsample{
public static void main(String[] args) {
try {
/*
* 擷取c可以有如下兩種方法
* */
//第一種推薦使用
Class c = Class.forName( "com.slowly.reflectTest.Son");
/*第二種不推薦使用
Son son = new Son();
Class c = son.getClass();
*/
Son s = (Son) c.newInstance();
System. out.println( "=======調用建立對象的方法=======" );
s.methodsonProtected();
s.methodSon();
s.methodFather();
//列印加載類的詳細資訊
System. out.println( "=====加載類的詳細資訊======" );
System. out.println( c.getName()+ "類自己聲明了" +c .getDeclaredFields().length +"個成員變量" );
System. out.println( "類自己公布的方法有" +c .getMethods().length +"個" );
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
輸出結果:
Field類的例子
import java.lang.reflect.*;
class Student{
public int age;
private int id;
public boolean gender;
public String name;
public Student( int age, int id, boolean gender,String name){
this. age = age;
this. id = id;
this. gender = gender;
this. name = name;
}
}
public class Field {
public static void main(String[] args) {
Student tom = new Student(21,1001, true, "Tom");
//擷取Student對應的Class類對象
Class c = tom.getClass();
//擷取Student類所有可以通路的成員變量對應的Filed數組
java.lang.reflect.Field[] fieldarray = c.getFields();
//列印Student類對象各成員變量的詳細資訊
System. out.println( "成員變量名\t\t成員變量類型\t\t成員變量值" );
int size = fieldarray. length;
//循環處理Filed數組
for ( int i = 0; i< size; i++) {
java.lang.reflect.Field tempf = fieldarray[i];
//列印輸出成員變量名稱
System. out.print( tempf.getName()+ "\t\t");
//列印成員變量類型
System. out.print( tempf.getType().toString()
+( tempf.getType().toString().length()>7? "\t": "\t\t"));
try {
//列印成員變量值
System. out.println( tempf.get( tom));
} catch (IllegalArgumentException | IllegalAccessException e ) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
顯示結果: 可以看出,程式列印了正确的成員變量資訊,包括age、gender、name成員變量。 而id由于是私有成員,不能在Student類外通路,是以沒有列印。
三、Method的介紹及例子
對于invoke()方法有如下幾點需要注意 不管實際對應方法的傳回值為什麼類型,都作為Object類型傳回。若傳回為基本資料類型,則傳回對應封裝類的對象。 obj參數指出要被調用方法所屬的對象,若調用靜态的方法用null值。 args指出要被調用方法的參數序列,若方法沒有參數則傳遞空數組---new Object[0],若方法有基本資料類型的參數則使用基本資料類型的封裝對象。
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class ForMethod{
//聲明靜态方法
public static void sayHello(String name){
System. out.println( "你好" +name +"!!!" );
}
public String generateNum( int max, int min){
return (Math. random()*( max- min)+ min)+ "";
}
}
public class method {
public static void main(String[] args) throws Exception {
//建立ForMethod類對象
ForMethod fm = new ForMethod();
//擷取ForMethod類對象對用的Class對象
Class fmc = fm.getClass();
//擷取可以通路的對象的對應的Method數組
Method[] md = fmc.getMethods();
System. out.println( "方法名稱\t\t傳回值類型\t\t參數清單" );
int size = md. length;
for( int i = 0; i< size; i++){
Method tempm = md[ i];
//列印方法名稱
String name = tempm.getName();
System. out.print( name+( name.length()>7? "\t": "\t\t"));
//列印方法的傳回值類型
String returntype = tempm.getReturnType().getName();
System. out.print( returntype+(( returntype.length()>15)? "\t":( returntype.length()>10)? "\t\t": "\t\t\t"));
//列印方法的參數序列
Class[] ca = tempm.getParameterTypes();
int csize = ca. length;
if( csize==0){
System. out.println( "沒有參數!!" );
}
else
for( int j = 0; j< csize; j++){
System. out.print( ca[ j].getName()+(( j== csize-1)? "": ","));
}
//換行
System. out.println();
}
System. out.println( "=====通過反射調用靜态方法sayHello======" );
md[0].invoke( null, new Object[]{ "王強" });
//通過反射調用非靜态方法
System. out.println( "=====通過反射調用非靜态方法generateNum=======" );
System. out.println( md[1].invoke( fm, new Object[]{new Integer(100),new Integer(1000)}));
}
}
輸出結果:
2017年5月9号添加
對于上面的問題,是因為
getMethods
public Method[] getMethods() throws SecurityException
傳回一個包含某些 Method 對象的數組,這些對象反映此 Class 對象所表示的類或接口(包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口)的公共 member 方法。
傳回數組中的元素沒有排序,也沒有任何特定的順序。是以第二個圖顯示,方法的順序變了,對應的參數也就變了,是以會報錯!
可以參考
java反射中getDeclaredMethods和getMethods的差別
四、Constructor類的知識與應用 Consstructor類的對象代表一個構造器,攜帶構造器的相關資訊,與Field、Method·類類似,其對象也不能通過構造器建立,而是要使用Class對象提供的get()系列方法獲得。
例子:
import java.lang.reflect.Constructor;
class Student01{
String name;
int age;
//無參構造器
public Student01(){
name = "Tom";
age = 23;
}
//有參構造器
public Student01(String name, int age){
this. name = name;
this. age = age;
}
public void sayHello(){
System. out.println( "您好,我是" +name +"今年" +age +"歲了!" );
}
}
public class constructor {
public static void main(String[] args) {
try{
//擷取Student類的Class對象
Class sc = Student01. class;
//擷取可以通路構造器對應的Constructor數組
Constructor[] ca = sc.getConstructors();
//對數組進行掃描列印構造器資訊
System. out.println( "構造器名\t\t\t\t\t\t參數清單" );
int size = ca. length;
//System.out.println(size+"");
for( int i = 0; i< size; i++){
Constructor tempc = ca[ i];
//列印構造器的名字
String cname = tempc.getName();
System. out.print( cname+ "\t\t");
//循環列印構造器的序列參數
Class[] pm = tempc.getParameterTypes();
int psize = pm. length;
if( psize==0){
System. out.println( "沒有參數!" );
}
else
for( int j = 0; j< psize; j++){
System. out.print( pm[ j].getName()+(( j== psize-1)? "": ","));
}
//換行
System. out.println();
}
//使用反射調用無參構造器
Student01 stu = (Student01) ca[0].newInstance( new Object[0]);
//調用建立對象的方法
stu.sayHello();
//使用反射調用有參構造器
Student01 stu01 = (Student01) ca[1].newInstance( "王強" ,new Integer(25));
//調用建立對象的方法
stu01.sayHello();
} catch(Exception e){
e.printStackTrace();
}
}
}
運作結果: