动态编程(一):反射

一、反射机制

1.1概念

在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

主要提供了以下功能:

  • 在运行时判断任意一个对象所属的类。
  • 在运行时构造任意一个类的对象。
  • 在运行时判断任意一个类所具有的成员变量和方法。
  • 在运行时调用任意一个对象的方法

1.2应用场合

反射的重点在于运行时阶段,可以动态加载和获取。常见的应用场合:

  • 访问没有权限的方法或属性
  • 编码阶段不能确定需要创建的类
  • 处理注解
  • 动态代理

1.3特点

优点:
提升程序的灵活性和扩展性
缺点:
破坏代码的封装性和可读性
性能差。反射相当于一系列解释操作,通知jvm要做的事情,性能比直接的java代码要慢很多。

二、API

2.1常用类

java.lang.Class; //类               
java.lang.reflect.Constructor;//构造方法 
java.lang.reflect.Field; //类的成员变量       
java.lang.reflect.Method;//类的方法
java.lang.reflect.Modifier;//访问权限

2.2获取Class对象

/**
 * 方式一:调用某个对象的getClass()方法
 */
User p=new User();
Class clazz=user.getClass();
/**
 * 方式二:调用某个类的class属性来获取该类对应的Class对象
 */
Class clazz=User.class;
/**
 * 使用反射:使用Class类中的forName()静态方法;
 */
Class clazz=Class.forName("com.lin.app.test.User");

2.3 Class API

//是否是基础类型
boolean isPrimitive = class1.isPrimitive();
//是否是集合类
boolean isArray = class1.isArray();
//是否是注解类
boolean isAnnotation = class1.isAnnotation();
//是否是接口类
boolean isInterface = class1.isInterface();
//是否是枚举类
boolean isEnum = class1.isEnum();
//是否是匿名内部类
boolean isAnonymousClass = class1.isAnonymousClass();
//是否被某个注解类修饰
boolean isAnnotationPresent = class1.isAnnotationPresent(Deprecated.class);
//获取class名字 包含包名路径
String className = class1.getName();
//获取class的包信息
Package aPackage = class1.getPackage();
//获取class类名
String simpleName = class1.getSimpleName();
//获取class访问权限
int modifiers = class1.getModifiers();
//内部类
Class[] declaredClasses = class1.getDeclaredClasses();
//外部类
Class declaringClass = class1.getDeclaringClass();

2.4创建类实例

        /**
         * 方式一:使用默认构造函数创建
         * 调用Class.newInstance()
         * 或通过Constructor.newInstance
         */
        try {
            Class clazz = User.class;
            User user = (User) clazz.newInstance();
            Constructor constructor = clazz.getConstructor();
            User user1 = (User) constructor.newInstance();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        /**
         * 方式二:使用带参构造函数创建
         * 调用Constructor.newInstance
         */
        try {
            Class clazz = User.class;
            Constructor constructor = clazz.getDeclaredConstructor(String.class, String.class);
            User user = (User) constructor.newInstance("", "");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

2.5方法和字段相关API

常用Field API
            /**
             * Class:
             * Field getField(String name)      获得类声明的指定公共字段(无法获取Private字段)
             * Field[] getFields()              获得类声明的所有公共字段(无法获取Private字段)
             * Field getDeclaredField(String name)  获取类声明的指定字段
             * Field[] getDeclaredFields()          获取类声明的所有字段
             *
             * Field:
             * getType()            返回这个变量的类型
             * getGenericType()     如果当前属性有签名属性类型就返回,否则就返回 Field.getType()
             * isEnumConstant()     判断这个属性是否是枚举类
             * getModifiers()       获取语言修饰符 public、private等
             * getName()            获取属性的名字
             * get(Object obj)      获取该对象属性值
             * set(Object obj, Object value) 设置该对象属性值
             * setAccessible(boolean flag)   设置允许访问private对象
             */
常用Method API
            /**
             * Class:
             * getMethods();                                        获取类声明的公共方法(无法获取Private方法)
             * getMethod(String name, Class... parameterTypes)   获取类声明的指定公共方法(无法获取Private方法)
             * getDeclaredMethods();                                获取类声明的所有方法
             * getDeclaredMethod(String name, Class... parameterTypes) 获取类声明的指定方法
             *
             * Method:
             * getDeclaringClass()              返回方法所在的Class
             * getParameterTypes()              形参类型
             * getExceptionTypes()              抛出的异常类型
             * getReturnType()                  返回类型
             * getModifiers()       获取语言修饰符 public、private等
             * getName()            获取方法名称
             * setAccessible(boolean flag)      设置允许访问private对象
             * isBridge()                       是否是桥接方法
             * isSynthetic()                    是否是复合方法
             * isVarArgs()                      是否带有可变参数
             * invoke(Object obj, Object... args)调用方法
             * getAnnotation(Class annotationClass) 获取注解信息
             */

三、示例

public class Test {
    public void getClazz() {
        //方式一:使用默认构造函数创建
        try {
            Class clazz = User.class;
            User user = (User) clazz.newInstance();
            Constructor constructor = clazz.getConstructor();
            User user1 = (User) constructor.newInstance();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        //方式二:通过Constructor.newInstance创建
        try {
            Class clazz = User.class;
            Constructor constructor = clazz.getDeclaredConstructor(String.class, String.class);
            User user = (User) constructor.newInstance("", "");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        try {
            Class clazz = Class.forName("com.lin.app.test.User");
            Object obj = clazz.getDeclaredConstructor(String.class, String.class).newInstance("姓名", "地址");
            Field address = clazz.getDeclaredField("address");
            //设置允许访问private对象
            address.setAccessible(true);
            //获取address的值
            print("before ", address.getName(), address.get(obj).toString());
            //改变address的值
            address.set(obj, "成都");
            print("after ", address.getName(), address.get(obj).toString());

            Method setMethod=clazz.getDeclaredMethod("setName",String.class);
            //设置允许访问private对象
            setMethod.setAccessible(true);
            Method getMethod=clazz.getDeclaredMethod("getName",String.class);
            getMethod.setAccessible(true);
            print("before",getMethod.getName(),((String)getMethod.invoke(obj)));
            setMethod.invoke(obj,"张三");
            print("after",getMethod.getName(),((String)getMethod.invoke(obj)));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    private void print(String... msg) {
        StringBuilder builder = new StringBuilder();
        for (String s : msg) {
            builder.append(s).append(" - ");
        }
        if (builder.length() > 0) {
            builder.deleteCharAt(builder.length() - 2);
        }
        Log.e(getClass().getSimpleName(), builder.toString());
    }
}

public class User {
    private String name;
    private String address;

    public User() {
    }

    public User(String name, String address) {
        this.name = name;
        this.address = address;
    }

    private String getName() {
        return name;
    }

    private void setName(String name) {
        this.name = name;
    }
}

你可能感兴趣的:(动态编程)