java Reflection(反射)基礎知識講解

原文連接:小ben馬java Reflection(反射)基礎知識講解java

1.獲取Class對象的方式

1.1)使用 "Class#forName"git

public static Class<?> forName(String className) throws ClassNotFoundException;

若是沒有獲取到Class對象,則拋出異常 ClassNotFoundException;github

eg:數組

Class<?> customerClazz = Class.forName("cn.xiaobenma.demo.core.reflection.VipCustomer");

1.2)使用某個類的 ".class",eg:code

Class<?> customerClazz = VipCustomer.class;

1.3)某個對象的 "#getClass()",eg:component

VipCustomer customer = new VipCustomer("001", "小ben馬", "10086", VipCustomer.VIP_ADVANCED);
Class<?> customerClazz = customer.getClass();

2.判斷是否爲某個類的實例

咱們一般使用 "instanceof" 來判斷對象是否爲某個類的實例。一樣,能夠使用 "Class#isInstance()" 來判斷對象

public native boolean isInstance(Object obj);

例子:blog

boolean isCustomer = customer instanceof VipCustomer;

isCustomer = VipCustomer.class.isInstance(customer);

若是person爲null, 上述例子都返回false。索引

3. 建立實例

3.1)使用 "Class#newInstance()": 要保證能訪問類的無參構造方法ip

public T newInstance() throws InstantiationException, IllegalAccessException;

3.2)經過 "Constructor#newInstance(Object ... initargs)"

public T newInstance(Object ... initargs)
    throws InstantiationException, IllegalAccessException,
           IllegalArgumentException, InvocationTargetException

eg:

Constructor<VipCustomer> constructor = getVipCustomerClass().getConstructor(String.class, String.class, String.class, int.class);
        VipCustomer customer = constructor.newInstance("001", "小ben馬", "10086", VipCustomer.VIP_ADVANCED);

4. 獲取方法(類方法、成員方法)

在Class中定義的方法以下:

//a. 獲取當前類及其父類,全部`public`類方法和成員方法
public Method[] getMethods() throws SecurityException;

//b. 經過方法名、參數類型,獲取單個`public`類方法或者成員方法(當前類或父類定義的)
public Method getMethod(String name, Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException;
        
//c. 獲取當前類(不包括超類)定義的全部類方法和成員方法        
public Method[] getDeclaredMethods() throws SecurityException;

//d. 經過方法名、參數類型,獲取單個當前類(不包括超類)定義的類方法或成員方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException;

5. 獲取構造方法

在Class中定義的方法以下:

//a. 獲取當前類全部`public`構造方法
public Constructor<?>[] getConstructors() throws SecurityException;

//b. 根據參數類型,獲取當前類單個`public`構造方法
public Constructor<T> getConstructor(Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException;

//c. 獲取當前類全部構造方法
public Constructor<?>[] getDeclaredConstructors() throws SecurityException;

//d. 根據參數類型,獲取當前類單個構造方法
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException;

6. 獲取變量(類變量、成員變量)

在Class中定義的方法以下:

//a. 獲取當前類及其超類,全部`public`類變量和成員變量
public Field[] getFields() throws SecurityException;

//b. 經過名稱,獲取當前類或超類,單個`public`類變量或者成員變量
public Field getField(String name)
        throws NoSuchFieldException, SecurityException;

//c. 獲取當前類(不包括超類),全部類變量和成員變量
public Field[] getDeclaredFields() throws SecurityException;

//d. 經過名稱,獲取當前類(不包括超類),單個類變量或成員變量
public Field getDeclaredField(String name)
        throws NoSuchFieldException, SecurityException;

7. 經過inovke,調用對象的方法

eg:

Method setRank = getVipCustomerClass().getDeclaredMethod("setRank", int.class);
setRank.invoke(customer, VipCustomer.VIP_NORMAL);

8.獲取和修改類變量或者成員變量的值

8.1) Field#set(Object obj, Object value): 經過對象和變量值,設置變量,eg:

Field field = getVipCustomerClass().getDeclaredField("rank");
field.set(customer, VipCustomer.VIP_ADVANCED);

8.2) Field#get(Object obj): 經過對象獲取變量值,eg:

Field field = getVipCustomerClass().getDeclaredField("rank");
int rank = (int) field.get(customer);

9.動態改變方法和變量的可訪問性

在使用反射獲取被調用類的構造方法、方法或變量,可能對於調用類是不可訪問的,如被調用類的"private"構造方法,"private" 方法, "private" 變量,會拋出 IllegalAccessException。
java能夠經過使用 "AccessibleObject#setAccessible(boolean flag)" 改變可訪問性。
"Constructor"、"Method" 和 "Field" 都是 "AccessibleObject" 的子類。

eg:

//在VipCustomer中定義類靜態常量PRI_NO=100
Field field = getVipCustomerClass().getDeclaredField("PRI_NO");
field.setAccessible(true);
Assert.assertEquals(100, field.get(null));

//私有構造方法
Constructor<VipCustomer> constructor = getVipCustomerClass().getDeclaredConstructor();
constructor.setAccessible(true);
VipCustomer customer = constructor.newInstance();
Assert.assertNull(customer.getCustomerNo());
Assert.assertNull(customer.getName());
Assert.assertNull(customer.getMobilePhone());

//調用私有類方法
Method method = getVipCustomerClass().getDeclaredMethod("doNothingByVipCustomer");
method.setAccessible(true);
method.invoke(null);

10.利用反射建立數組

數組是比較特殊的類型。

10.1) Array#newInstance(Class<?> componentType, int length),建立一維數組,eg:

//一維數組
Object array = Array.newInstance(String.class, 2);
Array.set(array, 0, "小ben馬");
Array.set(array, 1, "xiaobenma");

Assert.assertEquals("小ben馬", Array.get(array, 0));
Assert.assertEquals("xiaobenma", Array.get(array, 1));

10.2) Array#newInstance(Class<?> componentType, int... dimensions),建立多維數組,eg:

//多維數組
//String[2][1]
Object arrays = Array.newInstance(String.class, 2, 1);

Object array0 = Array.newInstance(String.class, 1);
Array.set(array0, 0, "小ben馬");
Array.set(arrays, 0, array0);

Object array1 = Array.newInstance(String.class, 1);
Array.set(array1, 0, "xiaobenma");
Array.set(arrays, 1, array1);

Assert.assertEquals("小ben馬", Array.get(Array.get(arrays, 0), 0));
Assert.assertEquals("xiaobenma", Array.get(Array.get(arrays, 1), 0));

10.3)Array#get(Object array, int index)

根據數組和相關索引獲取對應的值

10.4)Array#set(Object array, int index, Object value)

根據索引和相關索引,設置對應的值

11.Modifier說明

一般在類中

  • 定義構造方法格式: [修飾符列表] 類名([參數列表])。
  • 定義變量的格式爲: [修飾符列表] 返回類型 變量名稱。
  • 定義方法的格式爲: [修飾符列表] 返回類型 方法名([參數列表])。

"Member#getModifiers()" 返回一個int類型,經過解釋int的值,能獲取定義的修飾符列表。"Constructor"、"Method" 和 "Field" 都是 "Member" 的實現類。

修飾符返回的int值,須要經過 "Modifier" 解析。

其中,

  • Modifier#toString(int mod): 打印定義的全部修飾符
  • Modifier#isXXX(int mod): 判斷修飾符的類型

若是你看過Modifier的源碼,你會發現一個有趣的事情,修飾符是按bit位定義的,如:

/**
 * The {@code int} value representing the {@code public}
 * modifier.
 */
public static final int PUBLIC           = 0x00000001;

/**
 * The {@code int} value representing the {@code private}
 * modifier.
 */
public static final int PRIVATE          = 0x00000002;

/**
 * The {@code int} value representing the {@code protected}
 * modifier.
 */
public static final int PROTECTED        = 0x00000004;

ps說明

  • 反射相關包java.lang.reflect
  • Proxy是反射中比較重要的應用,在後續博客單獨更新。
  • 相關demo代碼 core-java-learning
相關文章
相關標籤/搜索