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;
    }
posted @ 2019-05-21 15:48  数据结构和算法  阅读(76)  评论(0编辑  收藏  举报