java反射詳解

獲取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;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章