10.反射
反射就是通過操作字節(jié)碼文件來做兩件事
- 創(chuàng)建對象
- 調(diào)用方法
對比硬編碼效率會低一些,但是代碼的靈活性大大提升
10.1 Class類 和 Class對象
運行Java程序,就是解析并且執(zhí)行字節(jié)碼文件鞠绰,而字節(jié)碼加載到JVM時腰埂,Java就會使用面向?qū)ο蟮乃枷氚鸭虞d過來的字節(jié)碼文件(class)封裝成對象
問題是這個字節(jié)碼文件在Java中是誰的對象蜈膨?
例如:
對象--> “123”,“aaa”驴一,“hello”
能描述以上對象的類型在Java中是String類型灶壶,所以以上是String的對象
對象--> 123,100胸懈,200
能描述以上對象的類型在Java中是Integer類型恰响,所以以上是Integer的對象
在Java中萬物皆對象,也就是說String和Integer也是對象首有,那他們到底是誰的對象呢?
對象--> String绞灼,Integer
能描述以上兩種對象的類型是什么呢低矮?
Class類是描述如String.class Integer.class等對象的類
Java中所有的類型都是Class的對象
類型相同, 它們的字節(jié)碼對象也都是相同的
10.2 反射創(chuàng)建對象
-
獲取Class對象
直接使用類名.class獲取字節(jié)碼文件對象
-
使用對象的方法getClass()獲取到對象的字節(jié)碼文件對象
這個方法是來自Object類
-
使用Class類的靜態(tài)方法forName(全限定名);
static Class<?> forName(String className) 通過類的全限定名獲取Class對象
-
無參構(gòu)造創(chuàng)建對象
//1.獲取類的字節(jié)碼對象 Class<?> clazz = Class.forName("com.example.mu.myapplication.TestCl"); //創(chuàng)建無參構(gòu)造的對象 TestCl instance = (TestCl) clazz.newInstance();
-
構(gòu)造器創(chuàng)建對象
如果字節(jié)碼對象不包含無參構(gòu)造,你就要通過獲取里面的構(gòu)造器再通過操作構(gòu)造器來創(chuàng)建對象
-
獲取字節(jié)碼對象中的構(gòu)造器
-
獲取public修飾的構(gòu)造器
Constructor<T> getConstructor(Class... parameterTypes) 返回一個構(gòu)造器,parameterTypes為構(gòu)造器參數(shù)的類型 Constructor<?>[] getConstructors() 獲得構(gòu)造器對象的數(shù)組
-
獲取任意的構(gòu)造器,包括私有的
Constructor<T> getDeclaredConstructor(Class... parameterTypes) Constructor<?>[] getDeclaredConstructors()
-
-
用構(gòu)造器創(chuàng)建對象
T newInstance(Object... initargs) Constructor的創(chuàng)建對象方法
-
示例代碼
Constructor<?> con= clazz.getConstructor(String.class); Object obj = con.newInstance("一個參數(shù)"); //這里的參數(shù)是對應構(gòu)造器的參數(shù) //無參構(gòu)造 con = clazz.getConstructor(null); Object o2 = con.newInstance(null); //私有構(gòu)造器 con = clazz.getDeclaredConstructor(String.class); con.setAccessible(true);//私有的構(gòu)造器需要設置訪問權(quán)限,暴力反射 con.newInstance("暴力反射");
-
-
方法對象
-
獲取字節(jié)碼對象中的方法對象
-
獲取public修飾的方法,包括從父類繼承的方法
Method getMethod(String name, Class... parameterTypes) 獲取指定的公共方法對象 name:方法名 parameterTypes:方法參數(shù)的類型 Method[] getMethods() 返回所有公共的方法對象的數(shù)組
-
獲取所有訪問權(quán)限的方法,包括私有的,但不包括從父類繼承的方法
Method getDeclaredMethod(String name, Class... parameterTypes) Method[] getDeclaredMethods()
-
-
Method對象調(diào)用方法
Object invoke(Object obj, Object... var2) obj:調(diào)用該方法的對象 var2:該方法的實參
-
示例代碼
lass<?> clazz = Class.forName("com.example.mu.myapplication.TestCl"); TestCl instance = (TestCl) clazz.newInstance(); //調(diào)用對象方法 Method m1 = clazz.getMethod("setName", String.class); m1.invoke(instance,"我是誰"); //不強制對象,調(diào)用對象的特有方法 String s = "123"; Method m2 = String.class.getMethod("length", null); Object o = m2.invoke(s, null);//invoke的返回值就是調(diào)用方法后的返回值 //調(diào)用私有的方法 Method work = clazz.getDeclaredMethod("work", null); work.setAccessible(true); work.invoke(instance,null); //調(diào)用靜態(tài)方法 Method m3 = clazz.getDeclaredMethod("lvup", null); //靜態(tài)方法不需要對象來調(diào)用,因此傳null m3.invoke(null,null);
-
-
字段對象
-
獲取Class對象中的Field對象
-
獲取public修飾的字段
Field getField(String name) name:字段名 Field[] getFields() 返回包含所有公共字段的數(shù)組
-
獲取所有訪問權(quán)限的字段
Field getDeclaredField(String name) Field[] getDeclaredFields()
-
-
Field對象,設置字段值和獲取字段值
Object get(Object obj) 獲取指定對象上的此字段的值 void set(Object obj, Object value) 將指定對象上的此字段設置為指定值
-
示例代碼
lass<?> clazz = Class.forName("com.example.mu.myapplication.TestCl"); TestCl instance = (TestCl) clazz.newInstance(); Field name = clazz.getField("name"); name.set(instance,"新名字");//設置值 name.get(instance);//獲取值
-
-
其他
int getModifiers() 獲取修飾符
Class對象,Method,Field都有的方法
int modifiers = name.getModifiers(); //將修飾符編碼轉(zhuǎn)出字符串 System.out.println(Modifier.toString(modifiers));