一個類有多個組成部分,例如:成員變量,方法,構造方法等。反射就是加載類,並解剖(反射)出類的各個組成部分。
本人在下面的反射例子中以註釋的形式把所理解的東西寫了出來java
Person類:數組
1 import java.util.List; 2 3 public class Person { 4 5 /* 6 * 1.構造方法 7 */ 8 //無參的 9 public Person(){ 10 System.out.println("無參的構造方法!"); 11 } 12 //一個參數,類型爲String的 13 public Person(String name){ 14 System.out.println("name:" + name); 15 } 16 //一個參數,類型爲int的,且爲私有的 17 private Person(int age){ 18 System.out.println("age:" + age); 19 } 20 //參數爲兩個參數 21 public Person(String name, int age){ 22 System.out.println(name + "的年齡:" + age + "歲"); 23 } 24 //參數爲List的 25 public Person(List list){ 26 System.out.println("list:" + list); 27 } 28 29 /* 30 * 2.普通方法 31 */ 32 //一、無參 33 public void methodTest(){ 34 System.out.println("這是無參的普通方法!"); 35 } 36 37 //二、一個參數 38 public void methodTest(String name){ 39 System.out.println("名字:" + name); 40 } 41 //三、一個參數私有的 42 private void methodTest(int age){ 43 System.out.println("年齡:" + age); 44 } 45 //四、兩個參數靜態的 46 public static void methodTest(String name, int age){ 47 System.out.println(name + "的年齡:" + age); 48 } 49 //五、main方法 50 public static void main(String[] args) { 51 System.out.println("main方法:"); 52 } 53 54 /* 55 * 3.字段 56 */ 57 public String name = "張三"; 58 private int age = 25; 59 private static String password = "PaSs1111"; 60 }
測試代碼:函數
1 import java.lang.reflect.Constructor; 2 import java.lang.reflect.Field; 3 import java.lang.reflect.InvocationTargetException; 4 import java.lang.reflect.Method; 5 import java.util.ArrayList; 6 import java.util.List; 7 8 import org.junit.Test; 9 10 public class ReflectTest { 11 12 /** 13 * @功能:反射 14 * @介紹: 15 * clazz1.getConstructor()中的參數是可變參數, 16 * 且用clazz1.getConstructor()只能反射出public型的,private反射不到 17 * 若是想要獲得private的構造方法,則須要用clazz.getDeclaredConstructor()來反射private的構造函數 18 * @日期:2013-10-22 19 */ 20 21 /* 22 * 1.構造方法反射 23 */ 24 @Test 25 public void test1() throws Exception{ 26 //加載類(方式一) 參數中類名要全稱 27 Class clazz1 = Class.forName("cn.itcast.reflect.Person"); 28 //加載類(方式二) ==> 實例化的時候構造方法直接運行 29 // Class clazz2 = new Person().getClass(); 30 //加載類(方式三) 31 // Class clazz3 = Person.class; 32 //反射無參的構造方法,null表示無參 33 Constructor c = clazz1.getConstructor(null); 34 //new一個對象(正常狀況下返回的是Object型的,這裏強轉爲Person) 35 Person p = (Person) c.newInstance(); 36 } 37 38 @Test 39 public void test2() throws Exception{ 40 //加載類 41 Class clazz = Class.forName("cn.itcast.reflect.Person"); 42 //解剖(反射)出參數爲String的構造方法(String.class) 43 Constructor c = clazz.getConstructor(String.class); 44 c.newInstance("張三"); 45 } 46 47 @Test 48 public void test3() throws Exception{ 49 //加載類 50 Class clazz = Class.forName("cn.itcast.reflect.Person"); 51 //解剖(反射)出參數爲int的構造方法(int.class) 52 /* 53 * 由於此時的構造方法爲private的,因此正常的clazz.getConstructor(),不能反射出來 54 * 此時就要用clazz.getDeclaredConstructor()來反射private的構造函數 55 * 但解剖出來的構造方法不能直接new一個新的對象,還得能過c.setAccessible(true)修改一下屬性(暴力反射) 56 * ,這時才能進行new新對象,和正常的反射同樣了 57 */ 58 Constructor c = clazz.getDeclaredConstructor(int.class); 59 //打開訪問權限 60 c.setAccessible(true); 61 c.newInstance(25); 62 } 63 64 @Test 65 public void test4() throws Exception{ 66 //加載類 67 Class clazz = Class.forName("cn.itcast.reflect.Person"); 68 //反射方法 69 Constructor c = clazz.getConstructor(String.class,int.class); 70 //new 71 c.newInstance("李四",25); 72 } 73 74 @Test 75 public void test5() throws Exception{ 76 //加載類 77 Class clazz = Class.forName("cn.itcast.reflect.Person"); 78 //反射方法 79 Constructor c = clazz.getConstructor(List.class); 80 //new 81 List list = new ArrayList(); 82 list.add("zhangsan"); 83 list.add("lisi"); 84 list.add("wangwu"); 85 list.add("zhaoliu"); 86 c.newInstance(list); 87 } 88 89 /* 90 * 2.普通方法反射 91 */ 92 @Test 93 public void test6() throws Exception{ 94 Person p = new Person(); 95 //加載類 96 Class clazz = Class.forName("cn.itcast.reflect.Person"); 97 98 /* 99 * 反射方法【clazz.getMethod("methodTest", null) 第一個參數爲:方法名;第二個參數爲:方法入參的類型】 100 * 這裏方法入參爲空,因此用null表示參數類型 101 */ 102 Method method = clazz.getMethod("methodTest", null); 103 //method.invoke(p, null) 第一個參數要傳一個對象,第二個爲所反射的方法入參 104 method.invoke(p, null); 105 } 106 107 @Test 108 public void test7() throws Exception{ 109 Person p = new Person(); 110 //加載類 111 Class clazz = Class.forName("cn.itcast.reflect.Person"); 112 //反射 113 Method method = clazz.getMethod("methodTest", String.class); 114 // 115 method.invoke(p, "張三"); 116 } 117 118 @Test 119 public void test8() throws Exception{ 120 Person p = new Person(); 121 //加載類 122 Class clazz = Class.forName("cn.itcast.reflect.Person"); 123 //私有的方法要用getDeclaredMethod來反射獲取 124 Method method = clazz.getDeclaredMethod("methodTest", int.class); 125 //反射出來的方法此時仍是private的,要強制打開訪問權限 126 method.setAccessible(true); 127 // 128 method.invoke(p, 25); 129 } 130 131 @Test 132 public void test9() throws Exception{ 133 //加載類 134 Class clazz = Class.forName("cn.itcast.reflect.Person"); 135 //反射 136 Method method = clazz.getMethod("methodTest", String.class, int.class); 137 /* 138 * 靜態的能夠不傳對象,爲:null便可 139 * (第一個參數爲傳對象的位置,後邊的參數都是把反射方法的入參,invoke的「第二個參數」即爲可變參數) 140 */ 141 method.invoke(null, "李四", 25); 142 } 143 144 @Test 145 public void test10() throws Exception{ 146 //加載類 147 Class clazz = Class.forName("cn.itcast.reflect.Person"); 148 Method method = clazz.getMethod("main", String[].class); 149 //main方法也是個靜態方法 150 /* 151 * 關於下邊註釋的部分,是不能夠用的,由於main方法中的參數爲String[] args,是一個數組,在這裏視爲一個參數 152 * 在jdk1.4以前,沒有「可變參數」,到了1.5之後纔有的可變參數 153 * 那麼,jdk1.4以前的method.invoke(String mehtodName, Object obj[])中 154 * 第二個參數用一個數組Object obj[]來傳參的,在invoke中會把這個數組拆解成爲一個個對應的參數 155 * 而jdk1.5是兼容jdk1.4的,因此,在jdk1.5中用數組來傳參也能夠,固然,它會把這個數組給拆解成幾個參數 156 * 所以,在調用main方法的時候,要在外圍再加一個數組,具體以下【數組參數1/2】 157 * 158 * 注:反射參數爲數組的方法都要注意 159 */ 160 //method.invoke(null, new String[]{"123","234"}); 161 //【數組參數1】 162 method.invoke(null, new Object[]{new String[]{"1234","5678","9012"}}); 163 //【數組參數2】也能夠這樣(前邊加一個Object能夠欺騙一下程序,騙它爲不是數組,其實傳進去的確實爲數組) 164 method.invoke(null, (Object)new String[]{"1234","5678","9012"}); 165 } 166 167 /* 168 * 3.字段反射 169 */ 170 171 @Test 172 public void test11() throws Exception{ 173 Person p = new Person(); 174 //加載類 175 Class clazz = Class.forName("cn.itcast.reflect.Person"); 176 //參數爲字段名稱 177 Field field = clazz.getField("name"); 178 //獲取字段值,傳一個對象進去 179 Object obj = field.get(p); 180 //獲取字段的類型 181 Class type = field.getType(); 182 //若是字段類型爲String,則打印數值 183 if(type.equals(String.class)){ 184 String value = (String) obj; 185 System.out.println(value); 186 } 187 //設置字段值,第一個參數傳一個對象,第二個參數爲修改的內容 188 field.set(p, "李四"); 189 //打印一下,看看能不能經過反射來改變字段的值(結果:能夠) 190 System.out.println(p.name); 191 } 192 193 @Test 194 public void test12() throws Exception{ 195 Person p = new Person(); 196 //加載類 197 Class clazz = Class.forName("cn.itcast.reflect.Person"); 198 // 199 Field field = clazz.getDeclaredField("age"); 200 //私有字段,修改訪問權限 201 field.setAccessible(true); 202 System.out.println(field.get(p)); 203 } 204 205 @Test 206 public void test13() throws Exception{ 207 Person p = new Person(); 208 //加載類 209 Class clazz = Class.forName("cn.itcast.reflect.Person"); 210 Field field = clazz.getDeclaredField("password"); 211 field.setAccessible(true); 212 /* 213 * 這裏,password字段爲私有且靜態的字段, 214 * 但靜態字段不一樣於靜態方法和靜態構造方法,field.get(p)中必須傳對象 215 */ 216 System.out.println(field.get(p)); 217 } 218 }