Java Reflect 反射機(jī)制
類字節(jié)碼文件是在硬盤上存儲(chǔ)的具壮,是一個(gè)個(gè)的.class文件准颓。我們?cè)趎ew一個(gè)對(duì)象時(shí)哈蝇,JVM會(huì)先把字節(jié)碼文件的信息讀出來放到內(nèi)存中,第二次用時(shí)攘已,就不用在加載了炮赦,而是直接使用之前緩存的這個(gè)字節(jié)碼信息。
字節(jié)碼的信息包括:類名样勃、聲明的方法吠勘、聲明的字段等信息。在Java中“萬物皆對(duì)象”峡眶,這些信息當(dāng)然也需要封裝一個(gè)對(duì)象剧防,這就是Class類、Method類辫樱、Field類峭拘。
通過Class類、Method類狮暑、Field類等等類可以得到這個(gè)類型的一些信息鸡挠,甚至可以不用new關(guān)鍵字就創(chuàng)建一個(gè)實(shí)例,可以執(zhí)行一個(gè)對(duì)象中的方法搬男,設(shè)置或獲取字段的值拣展,這就是反射技術(shù)。
- Class類
-
獲取Class對(duì)象的三種方式
Java中有一個(gè)Class類用于代表某一個(gè)類的字節(jié)碼缔逛。- Java提供了三種方式獲取類的字節(jié)碼
- Class.forName("")方法用于加載某個(gè)類的字節(jié)碼到內(nèi)存中备埃,并使用class對(duì)象進(jìn)行封裝
- 類名.class
- 對(duì)象.getClass()
/** * 加載類的字節(jié)碼的3種方式 * @throws ClassNotFoundException */ @Test public void test() throws ClassNotFoundException { // 方式一 Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person"); // 方式二 Class clazz2 = Person.class; // JVM會(huì)先把字節(jié)碼文件的信息讀出來放到內(nèi)存中,第二次用時(shí)褐奴,就不用在加載了瓜喇, // 而是直接使用之前緩存的這個(gè)字節(jié)碼信息。 // clazz1 == clazz2 : true System.out.println("clazz1 == clazz2 : " + (clazz1 == clazz2)); // 方式三 Person p1 = new Person(); Class clazz3 = p1.getClass(); System.out.println("clazz3 == clazz2 : " + (clazz3 == clazz2)); }
- Java提供了三種方式獲取類的字節(jié)碼
-
通過Class類獲取類型的一些信息
- getName()類的名稱(全名歉糜,全限定名)
- getSimpleName()類的的簡單名稱(不帶包名)
- getModifiers(); 類的的修飾符
- 創(chuàng)建對(duì)象 無參數(shù)構(gòu)造創(chuàng)建對(duì)象 newInstance()
- 獲取指定參數(shù)的構(gòu)造器對(duì)象,并可以使用Constructor對(duì)象創(chuàng)建一個(gè)實(shí)例 Constructor<T> getConstructor(Class<?>... parameterTypes)
/** * 通過Class對(duì)象獲取類的一些信息 * @throws Exception */ @Test public void test2() throws Exception { Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person"); // 獲取類的名稱 String name = clazz1.getName(); System.out.println(name); // 獲取類的簡單名稱 System.out.println(clazz1.getSimpleName()); // Person // 獲取類的修飾符 int modifiers = clazz1.getModifiers(); System.out.println(modifiers); // 通過class對(duì)象找到所有的構(gòu)造方法 Constructor[] constructors = clazz1.getConstructors(); for( Constructor constructor : constructors){ System.out.println(" " + constructor); } // 通過class對(duì)象找到所有的構(gòu)造方法,包括私有方法 Constructor[] declaredConstructors = clazz1.getDeclaredConstructors(); for( Constructor constructor : declaredConstructors){ System.out.println(" " + constructor); } // 構(gòu)建對(duì)象(默認(rèn)調(diào)用無參數(shù)構(gòu)造.) Object ins = clazz1.newInstance(); Person p = (Person) ins; System.out.println(p); // 獲取指定參數(shù)的構(gòu)造函數(shù) Constructor<?> con = clazz1.getConstructor(String.class, int.class); // 使用Constructor創(chuàng)建對(duì)象. Object p1 = con.newInstance("jack", 12); System.out.println(((Person) p1).getName()); // 通過私有構(gòu)造方法創(chuàng)建對(duì)象 Constructor constructor = clazz1.getDeclaredConstructor(String.class, int.class, int.class); // 設(shè)置構(gòu)造方法的訪問權(quán)限(暴力反射) constructor.setAccessible(true); Person p2 = (Person) constructor.newInstance("jj", 20, 1); System.out.println("p2.name = " + p2.getName()); }
-
通過Class類獲取類型中的方法的信息
1.獲取公共方法包括繼承的父類的方法 getMethods()返回一個(gè)數(shù)組,元素類型是Method
2.獲取指定參數(shù)的公共方法 getMethod("setName", String.class);
3.獲得所有的方法,包括私有 Method[] getDeclaredMethods()
4.獲得指定參數(shù)的方法,包括私有 Method getDeclaredMethod(String name, Class<?>... parameterTypes)/** * 獲取公有方法. * @throws Exception */ @Test public void test3() throws Exception { Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person"); // 1.獲取非私用方法(包括父類繼承的方法) Method[] methods = clazz1.getMethods(); System.out.println(methods.length); for (Method m : methods) { // System.out.println(m.getName()); if ("eat".equals(m.getName())) { m.invoke(clazz1.newInstance(), null); } System.out.println(" " + m.getName()); } } /** * 獲取指定方法簽名的方法 * * @throws Exception */ public void test4() throws Exception { Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person"); // 獲取指定名稱的函數(shù) // 第一個(gè)參數(shù)是方法名, 第二個(gè)參數(shù)是形參列表的數(shù)據(jù)類型 Method method1 = clazz1.getMethod("toString", null); // 執(zhí)行方法 // 第一個(gè)參數(shù): 方法的調(diào)用者(對(duì)象),第二個(gè)參數(shù): 方法執(zhí)行的第二個(gè)參數(shù) method1.invoke(new Person(), null); } /** * 獲取指定方法名且有參數(shù)的方法 * * @throws Exception */ @Test public void test5() throws Exception { Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person"); Method method = clazz1.getMethod("setName", String.class); method.invoke(new Person(), "包子"); } /** * 獲取指定方法名,參數(shù)列表為空的方法. * * @throws Exception */ @Test public void test6() throws Exception { Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person"); // 獲取指定名稱的函數(shù) Method method1 = clazz1.getMethod("sayHello", null); method1.invoke(new Person(), null); } /** * 反射靜態(tài)方法 * @throws Exception */ @Test public void test8() throws Exception { Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person"); Method method = clazz1.getMethod("sayHi", null); method.invoke(null, null); }
-
通過Class類獲取類型中的字段的信息
- 獲取公共字段 Field[] getFields()
- 獲取指定參數(shù)的公共字段 Field getField(String name)
- 獲取所有的字段 Field[] getDeclaredFields()
- 獲取指定參數(shù)的字段,包括私用 Field getDeclaredField(String name)
/** * 獲取公有的字段 */ @Test public void test9() throws Exception { Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person"); Field[] fields = clazz1.getFields(); Person p = new Person(); System.out.println(fields.length); for (Field f : fields) { System.out.println(f.getName()); if ("name".equals(f.getName())) { System.out.println(f.getType().getName()); f.set(p, "jack"); } } System.out.println(p.getName()); } /** * 獲取私有的字段 * @throws Exception */ @Test public void test10() throws Exception { Class clazz1 = Class.forName("cn.huangmp.java.api.reflect.Person"); Field field = clazz1.getDeclaredField("age"); System.out.println(field.getName()); field.setAccessible(true); Person p = new Person(); field.set(p, 100); System.out.println(p.getAge()); }
-