簡介Java反射基礎

【參考資料: 瘋狂Java講義 Chapter 18】java

一、類加載、鏈接、初始化數組

  當Java程序須要某一個類時,若是該類還沒有加載到內存中,系統會經過加載、鏈接、初始化三個步驟將該類加載到內存,並完成初始化工做。函數

  • 類加載:將類的class文件加載到內存,併爲之建立一個java.lang.Class對象。類的加載是經過類加載器,類加載器由JVM提供,統稱爲系統類加載器。除了利用JVM提供的類加載器,咱們還可經過繼承java.lang.ClassLoader來編寫本身的類加載器。一旦一個類被載入JVM,同一個類(用類的全限定名和類的類加載器做爲惟一標識)就不會被重複載入了。
  • 類鏈接:將類的二進制數據合併到JRE中。
  • 類初始化:JVM對類進行初始化,主要是針對靜態屬性進行初始化。

二、類加載器spa

  JVM啓動時,會造成由三個類加載器類組成的初始類的加載器層次結構:code

  • 根類加載器(Bootstrap classLoader):負責加載Java的核心類。根類加載器是由JVM自身實現的,並不是ClassLoader的子類。
  • 擴展類加載器(Extension ClassLoader):負責加載JRE的擴展目錄(JAVA_HOME/jre/lib/ext或者由java.ext.dirs屬性所指定的目錄)中JAR的類包。
  • 系統類加載器(System ClassLoader):在JVM啓動時,負責加載來自命令java中的-classpath或java.class.path系統屬性或CLASSPATH環境變量所指定的JAR包和類路徑。程序中可經過ClassLoader.getSystemClassLoader()獲取該類加載器。

  三個類加載器之間的層次關係:component

  

三、經過反射操做類對象

1)獲取java.lang.Class對象的經常使用方式blog

  • Class類的靜態方法forName(String className)。其中傳入的className參數爲類的全限定名。
  • 調用類的class屬性來獲取該類的Class對象。如Class strClass = String.class。
  • 調用對象的getClass()方法。

2)Class類提供的接口繼承

  獲取Class對象所對應類的構造器的接口:接口

1 Constructor<T> getConstructor(Class<?>... parameterTypes) //返回對應該類的public的構造器,構造器參數列表的類型聲明次序符合parameterTypes類型聲明次序,被封裝成了Constructor對象
2 Constructor<?>[] getConstructors() //獲取全部public構造器
3 Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) //返回對應parameterTypes類型聲明次序的該類的構造器,與訪問級別無關
4 Constructor<?>[] getDeclaredConstructors()//返回全部的構造器,與訪問級別無關

5 Constructor<?> getEnclosingConstructor() //用於匿名類或內部類

  獲取Class對象對應類的方法的接口:

1 Method getMethod(String name, Class<?>... parameterTypes); //返回由方法名name和參數列表類型parameterTypes限定的public方法
2 Method[] getMethods(); //全部public方法
3 Method getDeclaredMethod(String name, Class<?>... parameterTypes); //返回由方法名和參數列表類型parameterTypes限定的方法,與訪問級別無關
4 Method[] getDeclaredMethods(); //全部方法

5 Method getEnclosingMethod(); //用於獲取內部類或匿名類的方法

  獲取Class對象對應類所包含的屬性的接口:

1 Field getField(String name); //返回對應name的public 屬性
2 Field[] getFields();  //全部public屬性
3 Field getDeclaredField(String name);
4 Field[] getDeclaredFields();

【注:方法名中帶有Declared的方法返回的構造器、方法或屬性等都是忽略訪問級別的;而不帶有Declared的方法返回public的類成員。】

  訪問Class對應類的註釋的接口:

1 <A extends Annotation> A getAnnotation(Class<A> annotationClass); //返回符合特定註解類型annotationClass的註解
2 Annotation[] getAnnotations(); //當前Class的全部註解
3 Annotation[] getDeclaredAnnotations(); //直接出如今當前元素上的註解

  Class中用於判斷該Class是否爲註釋類型、數組類型、接口類型的接口:

1 boolean isAnnotation();
2 boolean isAnnotationPresent(Class<? extends Annotation> annotationClass); //判斷是否出現了特定類型的註解
3 boolean isAnonymousClass();
4 boolean isArray();
5 boolean isEnum();
6 boolean isInstance(Object obj); //判斷obj類型是否與當前Class對應的類型兼容
7 boolean isInterface();
8 boolean isLocalClass();
9 boolean isPrimitive();

  其餘接口:

1 String getName();//返回該Class表明的類或接口的全稱
2 String getPackage(); //返回包名
3 String getSimpleName(); //Class對應類的簡稱
4 Class<? super T> getSuperclass(); //返回超類

  對於上述接口中出現的Class<?>... parameterTypes,是指定的參數列表的Class對象。如:

 1    public class ReflectionTest{
 2 
 3     private int privateAttribute = -1;
 4     public int publicAttribute = -2;
 5     
 6     public String publicStrAttribute = "DefaultString";
 7     
 8     
 9     public void info(){
10         System.out.println("This is info() of class ReflectionTest");
11     }
12     
13     public void info(String str){
14         System.out.println("This is info(String) of class ReflectionTest");
15     }
16     
17     public void info(String str, Integer num){
18         System.out.println("This is info(String, Integer) of class ReflectionTest");
19     }
20     
21     private void privateInfo(){
22         System.out.println("This is privateInfo method");
23     }
24  
25     public static void main(String[] args) throws Exception{
26         Class<ReflectionTest> testClass = ReflectionTest.class;
27   
28         Method info1 = testClass.getMethod("info", null);
29           System.out.println("方法參數列表長度: "+info1.getParameterTypes().length);
30       
31           Method info2 = testClass.getMethod("info", String.class);
32           System.out.println("方法參數列表長度: "+info2.getParameterTypes().length);
33       
34           Method info3 = testClass.getMethod("info", String.class, Integer.class);
35           System.out.println("方法參數列表長度: "+info3.getParameterTypes().length);
36     }
37 }

 3)經過反射生成並操做對象

  • 經過Class對象的newInstance方法
  • 經過Class對象獲取對應類的Constructor,再經過Constructor對象的newInstance方法
1         Class<ReflectionTest> testClass = ReflectionTest.class;
2         
3         //經過Class對象構造Class對應類的實例
4         ReflectionTest rt1 = testClass.newInstance();
5         Constructor constructor = testClass.getConstructor(null);
6         ReflectionTest rt2 = (ReflectionTest)constructor.newInstance(null);  //調用默認構造函數,參數列表爲空

【注:代碼基於ReflectionTest類】

4)調用方法

  • public方法,直接經過Method對象的Object invoke(Object obj,Object... args)方法;其中obj爲調用該方法的Class對應類的實例,args爲方法的參數。
1         Object newTest = constructor.newInstance(null);
2         Method info = testClass.getMethod("info", null);
3         info.invoke(newTest, null); 
  •  private方法,首先要調用Method類的setAccessible(boolean flag)方法,不然報錯:java.lang.NoSuchMethodException

  而後調用private方法:

1         Method privateMethod = testClass.getDeclaredMethod("privateInfo", null); //獲取private方法使用getDeclaredMethod方法
2         privateMethod.setAccessible(true);
3         privateMethod.invoke(newTest, null);

 5)操做屬性值

  • 操做8個基本類型時,使用Field的getXXX(Object obj)或setXXX(Object obj, XXX value),其中obj爲被訪問的Class對應的類。
  • 操做引用類型時,使用Field的get(Object obj)或set(Object obj, Object value)
 1         //操做屬性
 2         Field privateField = testClass.getDeclaredField("privateAttribute"); //私有屬性
 3         System.out.println(privateField.getInt(newTest));
 4         privateField.setInt(newTest, -1000);
 5         System.out.println(privateField.get(newTest));
 6         
 7         Field strField = testClass.getField("publicStrAttribute"); //公有屬性
 8         System.out.println(strField.get(newTest));
 9         strField.set(newTest, "test value");
10         System.out.println(strField.get(newTest));

 6)操做數組

  java.lang.reflect包下含有Array類,Array類提供了能夠動態建立和訪問Java數組的靜態方法。

  主要接口:

1 static static Object newInstance(Class<?> componentType, int... dimensions); //多維度的數組
2 static Object newInstance(Class<?> componentType, int length); //指定數組長度的數組
3 
4 static XXX getXXX(Object array, int index);      //對於8中基本類型
5 static void setXXX(Object array, int index, XXX newValue);
6 
7 static Object get(Object array, int index);  //對於引用類型
8 static void setXXX(Object array, int index, Object newValue);
相關文章
相關標籤/搜索