獲取class
在java中一個類可以有多個對象,但只能有一個class對象,獲取類的方式有3中
Person mPerson = new Person();
Class c1 = mPerson.getClass();
Class c2 = Person.class;
Class c3 = Class.forName("com.wld.java.blogs.reflect.Person");
反射常用方法
getFields() //獲取所有public的屬性,包括從父類以及接口繼承的
getDeclaredFields() //獲取當前類的所有屬性,包括私有的
getField("fieldName") //獲取指定的屬性
getDeclaredField("fieldName") //獲取指定的屬性
getMethods() //獲取所有public的方法,包括從父類以及接口繼承的
getDeclaredMethods() //獲取當前類的所有方法,包括私有的
getMethod("methodName",Class... class) //獲取指定的方法
getDeclaredMethod("methodName",Class... class) //獲取指定的方法
getConstructors() //獲取當前類的所有public的構造函數,由於子類不能繼承父類的構造函數,所以獲取不到父類的構造函數
getDeclaredConstructors() //獲取當前類的所有構造函數,包括私有的
getConstructor(Class... class) //獲取指定的構造函數
getDeclaredConstructor(Class... class) //獲取指定的構造函數
getInterfaces()//獲取接口
getTypeParameters()//獲取泛型參數,結果爲數組,比如類Person<K, T>,獲取的結果爲K,T
如果要調用父類的私有屬性和方法要先獲取父類的class,比如獲取Person父類的class
Class superc = Person.class.getSuperclass();
獲取類的實例
假如有一個Person類有兩個構造函數,一個是無參的構造函數,一個是有兩個String類型參數的構造函數
Person mPerson1 = (Person) c.getDeclaredConstructor().newInstance();
Person mPerson2 = (Person) c.getDeclaredConstructor(String.class, String.class).newInstance("123", "456");//構造函數的參數類型
這兩種方式都可以創建類的實例。如果構造函數是私有的,在用上面方法就不行了。假如有兩個String參數的構造函數是私有的,在實例化之前要設置setAccessible(true);
Constructor mConstructor2 = c.getDeclaredConstructor(String.class, String.class);//構造函數的參數類型
mConstructor2.setAccessible(true);
Person mPerson2 = (Person) mConstructor2.newInstance("123", "456");//傳值
改變屬性的值
Class c = Person.class;
Object object = c.getDeclaredConstructor().newInstance();
Field field = c.getDeclaredField("publicPersonName");
field.set(object, "123");//如果publicPersonName是靜態的,object可以爲null
如果屬性是私有的必須要加field.setAccessible(true),它可以改變非final類型的所有屬性,包括靜態的,唯獨final類型是改變不了的,如果要改變final類型需要下面的這種方式
Class c = Person.class;
Object object = c.getDeclaredConstructor().newInstance();
Field field = c.getDeclaredField("privatePersonNameFinal");//字段名
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(object, "123");//對象和賦值
注意:屬性privatePersonNameFinal不能是基本類型,否則不會成功,如果不是基本類型就會成功,比如
private final String privatePersonNameFinal = new String("privatePersonNameFinal私有屬性");
如果換成
private final String privatePersonNameFinal = "privatePersonNameFinal私有屬性";
那麼屬性是改變不了的。
getModifiers()//獲取修飾符
比如我要判斷屬性name是否是final類型
Field field = c.getDeclaredField("name");
System.out.println(Modifier.isFinal(field.getModifiers()));
調用方法
Class c = Person.class;
Object object = c.getDeclaredConstructor().newInstance();
Method m = c.getDeclaredMethod("pWorkStatic", String.class);//方法名和參數類型
m.setAccessible(true);//如果方法是私有的需要添加
m.invoke(object, "789");//對象和傳參。如果是static,這裏的object可以爲null
獲取泛型的類型
比如一個類
public class Person extends Father<String, List>
我們可以獲取它的類型
Type type = c.getGenericSuperclass();
System.out.println(type);
ParameterizedType p = (ParameterizedType) type;
Class c1 = (Class) p.getActualTypeArguments()[0];
Class c2 = (Class) p.getActualTypeArguments()[1];
System.out.println(c1);
System.out.println(c2);
結果爲
com.wld.java.blogs.reflect.Father<java.lang.String, java.util.List> //前面com.wld.java.blogs.reflect是包名
class java.lang.String
interface java.util.List
這個可以根據它的類型來初始化,android開發中還是比較常用的,比如MVP中使用泛型的時候。
public static <T> T getT(Object o, int i) {
Type type = o.getClass().getGenericSuperclass();
if (type!=null){
if (type instanceof ParameterizedType){
ParameterizedType parameterizedType = (ParameterizedType) type;
Class<T> params = (Class<T>) parameterizedType.getActualTypeArguments()[i];
if (params!=null){
try {
return params.newInstance();
} catch (InstantiationException e) {
Logger.e(e.toString());
} catch (IllegalAccessException e) {
Logger.e(e.toString());
}
}
}
}
return null;
}