| 學員馮偉立(大二輟學,現廣州電信)聽完反射后的一句話:“反射就是把java類中的各種成分映射成相應的java類”。這句話比許多書上講的都透徹,都精辟! 我們先學完這些反射API后,后面再通過一個綜合案例來說明反射API的價值和作用。 |
二、反射API 2.1 Constructor類
例子:Constructor constructors[]=Class.forName("java.lang.String").getConstructors();
例子:Constructor constructor=Class.forName("java.lang.String").getConstructor(StringBuffer.class);
Constructor constructor=Class.forName("java.lang.String").getConstructor(StringBuffer.class); String ss=(java.lang.String)constructor.newInstance(/*"abc"*/new StringBuffer("abc"));
編譯器只看代碼的編譯,不看代碼的執行,我們開發人員一定要分清楚錯誤出現的不同階段。
如:Class.forName(("java.lang.String").newInstance();
//java.lang.Class源碼:
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) {//01.有緩存機制,說明得到某個類的構造器的字節碼是比較消耗資源的 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() { public Object run() { c.setAccessible(true); return null; } }); cachedConstructor = c;//02.把字節碼的構造器給緩存起來 } catch (NoSuchMethodException e) { throw new InstantiationException(getName()); } } Constructor<T> tmpConstructor = cachedConstructor;//03.把緩存構造器交給臨時變量 // Security check (same as in java.lang.reflect.Constructor) 安全檢查 int modifiers = tmpConstructor.getModifiers(); if (!Reflection.quickCheckMemberAccess(this, modifiers)) { Class caller = Reflection.getCallerClass(3); if (newInstanceCallerCache != caller) { Reflection.ensureMemberAccess(caller, this, null, modifiers); newInstanceCallerCache = caller; } } // Run constructor try { return tmpConstructor.newInstance((Object[])null);//04.調用構造器,返回該類實例 } catch (InvocationTargetException e) { Unsafe.getUnsafe().throwException(e.getTargetException()); // Not reached return null; } }
//源碼中之所以緩存構造器,是因為得到構造器的過程是比較消耗資源的。
2.2 Field類
package com.itcast.day1;public class ReflectPoint { //x是私有的, 01.要使用 字節碼.getDeclaredField("x") 獲得x的定義fieldX. //02.使用fieldX.setAccessible(true) 來進行暴力破解private訪問權限。 private int x; //y是共有的,用getField("y")就可以,也不涉及暴力破解權限。 public int y;//共有的 public ReflectPoint(int x, int y) { super(); this.x = x; this.y = y; } }
/***main方法中的測試代碼******成員變量的反射*********/ ReflectPoint rp=new ReflectPoint(2, 4); Field fieldY=rp.getClass().getDeclaredField("y"); //fieldY 值是多少? 4嗎?錯! //fieldY不是對象身上的變量,而是類上,要用它去取某個對象身上對應的值 System.out.println(fieldY.get(rp));//用fieldY去取對象rp上對應的變量y的值。 // Field fieldX=rp.getClass().getField("x");//Exception in thread "main" java.lang.NoSuchFieldException: x Field fieldX=rp.getClass().getDeclaredField("x"); fieldX.setAccessible(true);//暴力反射!解決: can not access a member of class com.itcast.day1.ReflectPoint with modifiers "private" System.out.println(fieldX.get(rp));
//javabeanpackage com.itcast.day1;public class ReflectFieldEx { private String firstName; private int age; private String address; public ReflectFieldEx(String firstName, int age, String address) { super(); this.firstName = firstName; this.age = age; this.address = address; } @Override public String toString() { return "ReflectFieldEx [firstName=" + firstName + ", age=" + age + ", address=" + address + "]"; } }
//利用反射來替換目標字符public static void change_a2b(Object obj )throws Exception{ Field[] fields=obj.getClass().getDeclaredFields(); for(int i=0;i<fields.length;i++){ if(fields[i].getType()==String.class){//字節碼在內存中只有一份,用==比較 ! fields[i].setAccessible(true); String fieldValue=fields[i].get(obj).toString(); if(fieldValue.contains("a")){ fieldValue=fieldValue.replace('a', 'b');//替換字符串中所有的a為b fields[i].set(obj,fieldValue); } } } }
ReflectFieldEx rfe=new ReflectFieldEx("a1b2c3", 2, "library"); System.out.println(rfe); change_a2b(rfe); System.out.println(rfe); ReflectFieldEx [firstName=a1b2c3, age=2, address=library] ReflectFieldEx [firstName=b1b2c3, age=2, address=librbry]
2.3 Method類
Method methodCharAt=Class.forName("java.lang.String").getMethod("charAt", int.class);
--------用反射方法執行某個類中的main方法
/***********成員方法的反射***********/ Method methodCharAt=Class.forName("java.lang.String").getMethod("charAt", int.class); System.out.println(s.charAt(1));//普通方式調用charAt方法 System.out.println(methodCharAt.invoke(s, 1));//反射方式,使用對象s,并傳遞參數1,調用methodCharAt代表字節碼的方法。 System.out.println(methodCharAt.invoke(s, new Object[] { 2 }));//按照jdk1.4語法調用(還沒有可變參數) //main方法反射調用--右鍵—run as—configuration—arguements填寫將要測試main方法所在的類名 Method methodMain=Class.forName(args[0]).getMethod("main", String[].class); //methodMain.invoke(null,new String[]{"xxxx","yyy","zzz"});//01. 會按照jdk1.4的語法進行處理,即把數組打散成為若干個單獨的參數 methodMain.invoke(null,new Object[]{new String[]{"xxxx","yyy","zzz"}});//02. 依然按照jdk1.4語法,參數打散后發現,里面只有一個元素--Stirng[] methodMain.invoke(null, (Object)new String[]{"xxxx","yyy","zzz"});//03.按照jdk1.5語法,參數不會被打散 //數組的反射 int [] a1=new int[]{1,2,3};//一維基本類型數組 int [] a2=new int[4]; int [][] a3=new int[2][3];//二維基本類型數組 = 一維數組中的元素為一維數組 = {int[3],int[3]} = 一維引用類型數組 String[] s1=new String[]{"a","b","c"};//一維引用類型數組 System.out.println(a1.getClass()==a2.getClass()); //打印數組--我們最想看到的是 每個元素被打印出來 System.out.println(a1); System.out.println(s1); //基本類型的一維數組可以被當作Object類型使用,不能當作Object[]類型使用, //非基本類型的一維數組,即可以當做Object類型使用,又可以當作Object[]類型使用。 //Arrays.asList()方法處理int[]和String[]時的差異 System.out.println(Arrays.asList(a1));//[[I@7b11a3ac] int[3]-->Object System.out.println(Arrays.asList(s1));//[a, b, c] String[3]-->Object[]{"a","b","c"}-->List //[[I@35d9dc39, [I@72093dcd] int[2][3]-->int[]{int[3],int[3]}-->Object[]{int[3],int[3]}-->Object[]{Object,Object} System.out.println(Arrays.asList(a3));
//利用數組的反射打印private static void printObject(Object obj) { Class clazz=obj.getClass(); if(clazz.isArray()){ int len=Array.getLength(obj); for(int i=0;i<len;i++){ System.out.println(Array.get(obj, i)); } }else{ System.out.println(obj); } } //測試代碼 int [] a1=new int[]{1,2,3};String[] s1=new String[]{"a","b","c"};printObject(a1);//打印int[] printObject(s1);//打印String[] printObject("xxx");//打印字符串運行結果:1 2 3 a b c 思考題:怎么得到數組中的元素類型?
沒有辦法,因為Object[]里可以放各種東西,我們只能得到某一個元素的類型,而不能得到Object[]的類型
Object[] a=new Object(){1,flase,”abc”};
a[0].getClass().getTYPE();//得到某一元素的類型
新聞熱點
疑難解答