Java 反射機制包 java.lang.reflect

Java的反射(reflection)機制是指在程序的運行狀態中,可以構造任意一個類的對象,可以瞭解任意一個對象所屬的類,可以瞭解任意一個類的成員變量和方法,可以調用任意一個對象的屬性和方法。這種動態獲取程序信息以及動態調用對象的功能稱爲Java語言的反射機制。

我們知道對於一個類或者說是class文件比較準確,是JVM將描述的類的數據從class文件加載到內存(方法區),並且對數據進行校驗和初始化,最終形成可以被虛擬機直接使用的Java類型。其實對於任何一個Java中的任意一個類型,都有一個對應的Class對象用於描述該類的數據,Class是Java反射機制的核心API,它是我們獲取類數據的基礎。一般來說,我們有三種方法去獲取一個類的Class對象:

package cn.org.microservice.java.reflection;
//創建一個類,然後獲取該類的Class對象
public class Reflection {
    .......
    //1.通過對象的方式獲取
    Reflection reflection = new Reflection();
    Class<? extends Reflection> clazz1 = reflection.getClass();
    //2.通過Class.forName()獲取
    String className = "cn.org.microservice.java.reflection.Reflection";
    Class<?> clazz2 = Class.forName(className);
    //3.直接通過類型.class獲取
    Class<Reflection> clazz3 = Reflection.class;
    //4.通過 通過ClassLoader的loadClass()獲取
    Class<?> clazz4 = ClassReflection.class.getClassLoader().loadClass(className);
    //代碼中clazz1,clazz2.clazz3.clazz4指向的是同一個Class對象
    //打印出的的是同一個對象
    System.out.println(clazz1 + "," + clazz2 + "," + clazz3+ "," + clazz4);
    System.out.println(clazz1.hashCode() + "," + clazz2.hashCode()+ "," + clazz3.hashCode() + "," + clazz4.hashCode());
}

每一個類都會對應且只有一個Class實例,這個示例存儲這該類的數據信息,包括包(Package),類名稱(String),全類名稱(String),構造方法(Constructor),方法(Method),字段(Field),父類(Class),接口(Class),註解等相關信息,我麼可以在運行時或者這些信息:相關API如下:

public class ClassReflection {
public static void main(String[] args) throws ClassNotFoundException {
    String className = "cn.org.microservice.java.reflection.Reflection";
    Class<Reflection> clazz1 = Reflection.class;
		
    //獲取包信息
    Package package1 = clazz1.getPackage();
    //獲取構造方法信息
    Constructor<?>[] constructors = clazz1.getConstructors();
    Constructor<?> constructor = clazz1.getConstructor();
    //獲取字段信息,其中getField只能獲取public聲明的字段,getDeclaredField可以獲取所有字段
    Field field = clazz1.getField("name");
    Field[] fields1 = clazz1.getFields();
    Field field2 = clazz1.getDeclaredField("protectedField");
    Field[] fields2 = clazz1.getDeclaredFields();
    //獲取方法信息 其中getField只能獲取getMethod聲明的字段,getDeclaredMethod可以獲取所有字段
    Method Method1 = clazz1.getMethod("setName", String.class);
    Method[] Methods1 = clazz1.getMethods();
    Method Method2 = clazz1.getDeclaredMethod("privateMethod",int.class);
    Method[] Methods2 = clazz1.getDeclaredMethods();
    //獲取接口信息
    Class <?>[] clazzs1 = clazz1.getInterfaces();
    Type [] interfacetypes = clazz1.getGenericInterfaces();
    //獲取父類信息
    Class<? super Reflection> clazzs2 = clazz1.getSuperclass();
    Type superClasstypes = clazz1.getGenericSuperclass();
    //獲取註解信息
    Annotation [] auAnnotations = clazz1.getAnnotations();
    //獲取類的修飾符
    clazz1.getModifiers();
    //是否是接口
    clazz1.isInterface();
    //獲取全類名
    clazz1.getName();
    //獲取類名
    clazz1.getSimpleName();
    }
}

Field類:

Field類用於描述Class中的Field的相關信息。我們可以通過getField(s)獲取public修飾的字段、getDeclaredField(s)等方法獲取非public方法獲取的字段。然後通過Field實例獲取Field的相關信息:

String className = "cn.org.microservice.java.reflection.Reflection";
Class<?> clazz = Class.forName(className);
Field field = clazz.getField("name");
Reflection r = new Reflection();
// 獲取字段名稱
field.getName();
// 獲取字段上註解
Annotation[] annotations = field.getAnnotations();
//爲獲取Reflection的字段name的值
field.get(r);
//爲Reflection字段name設置值
field.set(r, "pharos");

Constructor類:

Constructor類用於描述Class中的Constructor的相關信息。我們可以通過getConstructor(s)獲取public修飾的構造方法、getDeclaredConstructor(s)等方法獲取非public修飾的構造方法。然後通過Constructor實例獲取Constructor的相關信息,並且可以通過構造方法實例化對象。下面是常用的Constructor API。

//通過無參構造方法實例化對象
Constructor<?> constructor = clazz.getConstructor();
Reflection reflection = (Reflection) constructor.newInstance();
//通過有參構造方法實例化對象
Constructor<?> constructor1 = clazz.getConstructor(String.class);
Reflection reflection1 = (Reflection) constructor1.newInstance("pharos");
Constructor<?> constructor1 = clazz.getConstructor(String.class);
Reflection reflection1 = (Reflection) constructor1.newInstance("pharos");

Constructor<?> constructor2 = clazz.getDeclaredConstructor(int.class);
//如果是非public修飾的構造方法,使用其初始化對象時,需要調用setAccessible,並設置爲true,可訪問
constructor2.setAccessible(true);
Reflection reflection2 = (Reflection) constructor2.newInstance(10);
//獲取構造方法上的註解
constructor.getAnnotations();
//獲取構造方法中參數註解
constructor.getParameterAnnotations();
//獲取所有參數
constructor.getParameters();
//獲取參數數量
constructor.getParameterCount();
//獲取參數類型
constructor.getParameterTypes();

Annotation類:一般我們使用getAnnotations()獲取到所有註解,然後根據不同的註解類型,做處理。

Annotation [] annotations = Reflection.class.getAnnotations();
for(Annotation annotation : annotations) {
    System.out.println(annotation.annotationType());
}

Package類:一把我們使用getPackage()獲取一個類的包,也可以通過靜態方法getPackages()獲取虛擬機加載的所有包。

Package package1 = Reflection.class.getPackage();
System.out.println(package1.getName());
Package [] package2 =Package.getPackages();
for(Package package3 : package2) {
    System.out.println(package3.getName());
}

Method類:Method類用於描述Class中的Method的相關信息。我們可以通過getMethod(s)獲取public修飾的方法,通過getDeclaredMethod(s)獲取非public修飾的方法。

Class<Reflection> clazz1 = Reflection.class;
Method method1 = clazz1.getDeclaredMethod("privateMethod", int.class);
Reflection instance = clazz1.newInstance();
//同構造方法類似,我麼可以獲取方法上的註解,參數中的註解,參數,參數類型,參數數量
method1.getAnnotations();
method1.getParameterAnnotations();
method1.getParameters();
method1.getParameterCount();
method1.getParameterTypes();
/獲取返回值類型
method1.getReturnType();

//我們可以通過invoke方法執行獲取到的方法
Method method1 = clazz1.getDeclaredMethod("privateMethod", int.class);
//與構造方法類似,如果是非public修飾的方法,調用前需要設置訪問屬性爲true,
method1.setAccessible(true);
method1.invoke(instance, 10);

其實Java的反射用起來還是比較簡單的,就是通過類的Class實例,獲取類的數據,然後根據獲取到的數據進行處理,詳細的Java 反射API 可以參考官方的java.lang.reflect包文檔

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章