Constructor類
Constructor 提供關於類的單個構造方法的信息以及對它的訪問權限。
Constructor 允許在將實參與帶有底層構造方法的形參的 newInstance() 匹配時進行擴展轉換,但是如果發生收縮轉換,則拋出 IllegalArgumentException。
示例代碼:

1 package reflect; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Field; 5 import java.lang.reflect.Method; 6 import java.util.Iterator; 7 8 public class ReflectTest { 9 10 /** 11 * @author alan 12 * @param args 13 * @throws Exception 14 */ 15 public static void main(String[] args) throws Exception { 16 /* 17 * Contructor類解析:類的構造方法沒有順序 Constructor 提供關於類的單個構造方法的信息以及對它的訪問權限。 18 * Constructor 允許在將實參與帶有底層構造方法的形參的 newInstance() 匹配時進行擴展轉換, 19 * 但是如果發生收縮轉換,則拋出 IllegalArgumentException。 20 * 21 * 反射比較占用時間,需要緩存。程序性能下降:查看Class源碼 22 * */ 23 System.out.println("Contructor類解析"); 24 Constructor constructor=String.class.getConstructor(StringBuffer.class); //getConstructor是可變參數,選擇構造方法(含一個字符串參數),運行時執行 25 String string2=(String) constructor.newInstance(new StringBuffer("string"));//通過參數來選擇構造方法創建實例。(與構造方法同樣類型的變量) 26 System.out.println(string2);// 編譯時無措:二進制代碼 運行時出錯:Exception in thread "main" java.lang.IllegalArgumentException: argument type mismatch 27 28 //String string3=(String) constructor.newInstance("string");//參數不同,運行時出錯 29 //System.out.println(string3); 30 } 31 }
Class 的newInstance()方法解析。newInstance ()中調用的newInstance0()方法使用緩存機制來保存默認構造方法的實例。
jdk源碼解析:
public T newInstance()
throws InstantiationException, IllegalAccessException
{
if (System.getSecurityManager() != null) {
checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader(), false);
}
return newInstance0();
}
private T newInstance0()
throws InstantiationException, IllegalAccessException
{
// NOTE: the following code may not be strictly correct under
// the current Java memory model.
// Constructor lookup
if (cachedConstructor == null) { //緩存為空
if (this == Class.class) {
throw new IllegalAccessException(
"Can not call newInstance() on the Class for java.lang.Class"
);
}
try {
Class<?>[] empty = {};
final Constructor<T> c = getConstructor0(empty, Member.DECLARED);//得到無參的構造方法構造實例對象。
// Disable accessibility checks on the constructor
// since we have to do the security check here anyway
// (the stack depth is wrong for the Constructor's
// security check to work)
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
c.setAccessible(true);
return null;
}
});
cachedConstructor = c; //將c緩存起來,下次調用newInstance時,直接讀取緩存並返回
} catch (NoSuchMethodException e) {
throw new InstantiationException(getName());
}
}
Constructor<T> tmpConstructor = cachedConstructor; //調用緩存內的實例對象創建tmpConstructor
Field類
Field 提供有關類或接口的單個字段的信息,以及對它的動態訪問權限。反射的字段可能是一個類(靜態)字段或實例字段。
Array 允許在執行 get 或 set 訪問操作期間進行擴展轉換,但如果將發生收縮轉換,則拋出一個 IllegalArgumentException。
示例代碼:

1 package reflect; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Field; 5 import java.lang.reflect.Method; 6 import java.util.Iterator; 7 8 public class ReflectTest { 9 10 /** 11 * @author alan 12 * @param args 13 * @throws Exception 14 */ 15 public static void main(String[] args) throws Exception { 16 17 18 /* 19 * Field類解析 Field 提供有關類或接口的單個字段的信息,以及對它的動態訪問權限。反射的字段可能是一個類(靜態)字段或實例字段。 20 * Array 允許在執行 get 或 set 訪問操作期間進行擴展轉換,但如果將發生收縮轉換,則拋出一個 21 * IllegalArgumentException。 22 */ 23 System.out.println("Field類解析:"); 24 ReflectPoint reflectPoint=new ReflectPoint(1, 2); 25 26 Field fieldX=reflectPoint.getClass().getField("x"); //x!=1對應到類字節碼的變量,沒有對應類對象身上。 27 System.out.println(fieldX.get(reflectPoint)); //在reflectPoint具體對象中的變量 28 29 Field fieldY=reflectPoint.getClass().getDeclaredField("y"); //y不可見 30 fieldY.setAccessible(true); //暴力反射 31 System.out.println(fieldY.get(reflectPoint)); 32 33 System.out.println("替換成員變量中的字符實驗"); 34 replaceWord(reflectPoint); //替換成員變量中的字符。 35 System.out.println(reflectPoint); 36 37 38 } 39 public static void replaceWord(Object object) throws Exception { 40 Field[] fields = object.getClass().getFields(); 41 for (Field field : fields) { 42 if (field.getType() == String.class) { // 只有一份字節碼,所以使用“==”比較,而非equals 43 String oldWord = (String) field.get(object); 44 String newWord = oldWord.replace("w", "W"); 45 field.set(object, newWord); 46 } 47 } 48 } 49 } 50 51
輔助ReflectPoint類代碼:

1 package reflect; 2 3 public class ReflectPoint { 4 public int x; 5 private int y; 6 public String string="helloworld"; 7 8 public ReflectPoint(int x, int y) { 9 super(); 10 this.x = x; 11 this.y = y; 12 } 13 14 public String toString () { 15 return "helloworld has changed to "+string; 16 } 17 }
Method類
Method 提供關於類或接口上單獨某個方法(以及如何訪問該方法)的信息。所反映的方法可能是類方法或實例方法(包括抽象方法)。
Method 允許在匹配要調用的實參與底層方法的形參時進行擴展轉換;但如果要進行收縮轉換,則會拋出 IllegalArgumentException。
1、 得到類中的某個方法,如下示:
Method chatAt=Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);
2、 調用方法,如下示:
通用方式:System.out.println(string.charAt(1));
反射方式:System.out.println(charAt.invoke(string,1));如果傳遞給Method對象的invoke()方法的一個參數為null時,說明Method對象對應的是一個靜態方法。
示例代碼:

1 package reflect; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Field; 5 import java.lang.reflect.Method; 6 import java.util.Iterator; 7 8 public class ReflectTest { 9 10 /** 11 * @author alan 12 * @param args 13 * @throws Exception 14 */ 15 public static void main(String[] args) throws Exception { 16 /* 17 * Method類解析 18 */ 19 System.out.println("Method類解析:"); 20 String string = "string"; 21 System.out.println("通用方式:"+string.charAt(1)); 22 Class class1 = string.getClass(); 23 Method charAtMethod = String.class.getMethod("charAt", int.class); 24 System.out.println("反射方式:"+charAtMethod.invoke(string, 1));// 指定對象string調用由此 Method對象charAtMethod表示的底層方法charAt(). 25 } 26 }
3、寫一個程序,程序能夠根據用戶提供的類名,去執行該類中的main方法。
示例代碼:

1 package reflect; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Field; 5 import java.lang.reflect.Method; 6 import java.util.Iterator; 7 8 public class ReflectTest { 9 10 /** 11 * @author alan 12 * @param args 13 * @throws Exception 14 */ 15 public static void main(String[] args) throws Exception { 16 17 //寫一個程序,程序能夠根據用戶提供的類名,去執行該類中的main方法 18 System.out.println("寫一個程序,程序能夠根據用戶提供的類名,去執行該類中的main方法:"); 19 TestArgument.main(new String[]{"1","2","3"}); //普通方式:類的靜態方法調用 20 //使用反射方式調用。源程序無法知道類的名稱, 21 String startString=args[0]; 22 Method mainMethod=Class.forName(startString).getMethod("main", String[].class); 23 //mainMethod.invoke(null, new String[]{"1","2","3"}); //出現錯誤Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments 24 mainMethod.invoke(null, new Object[]{ new String[]{"1","2","3"}}); //invoke第一個參數為null表示為靜態方法調用。 25 //mainMethod.invoke(null, (Object)new String[]{"1","2","3"}); 26 } 27 } 28 29 class TestArgument{ 30 public static void main(String[] args) { 31 for (String string : args) { 32 System.out.println(string); 33 } 34 35 } 36 37 }
問題:Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments
原因:jdk1.4語法中,數組中每個元素對應一個參數。為了兼容jdk1.4,javac會按jdk1.4語法處理。即把數組打散成為若干個單獨的參數。
解決方法:
1、mainMethod.invoke(null, new Object[]{ new String[]{"1","2","3"}}); //再包裝一層,拆后為實際所需的參數。此方法效率較低。
2、mainMethod.invoke(null, (Object)new String[]{"1","2","3"}); //給的是對象,不是數組,不會拆。編譯器會做特殊處理,編譯時不把參數當作數組對待,也就不會將數組打散為若干個參數了。