当前位置:职场发展 > 【168期】面试官:框架中处处可见反射的运用,你对它了解多少?

【168期】面试官:框架中处处可见反射的运用,你对它了解多少?

  • 发布:2023-09-28 06:42

什么是反射? 反射是一种能够在程序运行时动态访问、修改某个类中任意属性(状态)和方法(行为)的机制(包括private实例和方法),java反射机制提供了以下几个功能: 在运行时判断任意一个对象所属的类; 在运行时构造任意一个类的对象; 在运行时判断任意一个类所具有的成员变量和方法; 在运行时调用任意一个对象的方法。 反射涉及到四个核心类: www.sychzs.cn:类对象; www.sychzs.cn:类的构造器对象; www.sychzs.cn:类的方法对象; www.sychzs.cn:类的属性对象; 反射有什么用? 操作因访问权限限制的属性和方法; 实现自定义注解; 动态加载第三方jar包,解决android开发中方法数不能超过65536个的问题; 按需加载类,节省编译和初始化APK的时间; 反射工作原理 当我们编写完一个Java项目之后,每个java文件都会被编译成一个.class文件,这些Class对象承载了这个类的所有信息,包括父类、接口、构造函数、方法、属性等,这些class文件在程序运行时会被ClassLoader加载到虚拟机中。 当一个类被加载以后,Java虚拟机就会在内存中自动产生一个Class对象。我们通过new的形式创建对象实际上就是通过这些Class来创建,只是这个过程对于我们是不透明的而已。 反射的工作原理就是借助www.sychzs.cn、www.sychzs.cn、www.sychzs.cn、www.sychzs.cn这四个类在程序运行时动态访问和修改任何类的行为和状态。 反射实例 分别演示三种获取类信息的方式、获取当前类的所有方法和获取当前类及其父类的所有方法、获取当前类的所有实例和获取当前类及其父类的所有实例、获取父类信息、获取接口信息、比较反射方法和实例的性能差异等几个方面: 示例类: 父类www.sychzs.cn: public class ReflectActivity extends Activity{    @Override    protected void onCreate(Bundle savedInstanceState){        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_reflect_layout);    }     public void onClick(View v){        switch(v.getId()){            case R.id.getClassObjectBtnId:{                getClassObject();            }            break;            case R.id.getMethodInfoBtnId:{                getMethodInfo();            }            break;            case R.id.getFieldInfoBtnId:{                getFieldInfo();            }            break;            case R.id.getSuperClassInfoBtnId:{                getSuperClass();            }            break;            case R.id.getInterfaceInfoBtnId:{                getInterfaces();            }            break;            case R.id.compareMethodAndFieldBtnId:{                compareCallMethodAndField();            }            break;            default:{             }            break;        }    }     private void getClassObject(){        Class classObject = null;         classObject = getClassObject_1();        LogE("classObject_1 name : " + classObject.getName());        classObject = getClassObject_2();        LogE("classObject_2 name : " + classObject.getName());        classObject = getClassObject_3();        LogE("classObject_3 name : " + classObject.getName());    }     private void getMethodInfo(){        getAllMethods();        getCurrentClassMethods();    }     private void getFieldInfo(){        getAllFields();        getCurrentClassFields();    }     private void getSuperClass(){        ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);        Class superClass = programMonkey.getClass().getSuperclass();        while (superClass != null) {            LogE("programMonkey's super class is : " + superClass.getName());            // 再获取父类的上一层父类,直到最后的 Object 类,Object 的父类为 null            superClass = superClass.getSuperclass();        }    }     private void getInterfaces() {        ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);        Class[] interfaceses = programMonkey.getClass().getInterfaces();        for (Class class1 : interfaceses) {            LogE("programMonkey's interface is : " + class1.getName());        }    }     private void compareCallMethodAndField(){        long callMethodCostTime = getCallMethodCostTime(10000);        LogE("callMethodCostTime == " + callMethodCostTime);        long callFieldCostTime = getCallFieldCostTime(10000);        LogE("callFieldCostTime == " + callFieldCostTime);    }     private long getCallMethodCostTime(int count){        long startTime = System.currentTimeMillis();        for(int index = 0 ; index < count; index++){            ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);            try{                Method setmLanguageMethod = programMonkey.getClass().getMethod("setmLanguage", String.class);                setmLanguageMethod.setAccessible(true);                setmLanguageMethod.invoke(programMonkey, "Java");            }catch(IllegalAccessException e){                e.printStackTrace();            }catch(InvocationTargetException e){                e.printStackTrace();            }catch(NoSuchMethodException e){                e.printStackTrace();            }        }         return System.currentTimeMillis()-startTime;    }     private long getCallFieldCostTime(int count){        long startTime = System.currentTimeMillis();        for(int index = 0 ; index < count; index++){            ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);            try{                Field ageField = programMonkey.getClass().getDeclaredField("mLanguage");                ageField.set(programMonkey, "Java");            }catch(NoSuchFieldException e){                e.printStackTrace();            }catch(IllegalAccessException e){                e.printStackTrace();            }        }         return System.currentTimeMillis()-startTime;    }     /**     * 获取当前类中的所有方法     *     * */    private void getCurrentClassMethods() {        ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);        Method[] methods = programMonkey.getClass().getDeclaredMethods();        for (Method method : methods) {            LogE("declared method name : " + method.getName());        }         try {            Method getSalaryPerMonthMethod = programMonkey.getClass().getDeclaredMethod("getSalaryPerMonth");            getSalaryPerMonthMethod.setAccessible(true);            // 获取返回类型            Class returnType = getSalaryPerMonthMethod.getReturnType();            LogE("getSalaryPerMonth 方法的返回类型 : " + returnType.getName());             // 获取方法的参数类型列表            Class[] paramClasses = getSalaryPerMonthMethod.getParameterTypes() ;            for (Class class1 : paramClasses) {                LogE("getSalaryPerMonth 方法的参数类型 : " + class1.getName());            }             // 是否是 private 函数,属性是否是 private 也可以使用这种方式判断            LogE(getSalaryPerMonthMethod.getName() + " is private " + Modifier.isPrivate(getSalaryPerMonthMethod.getModifiers()));             // 执行方法            Object result = getSalaryPerMonthMethod.invoke(programMonkey);            LogE("getSalaryPerMonth 方法的返回结果: " + result);        } catch (Exception e) {            e.printStackTrace();        }    }     /**     * 获取当前类和父类的所有公有方法     *     * */    private void getAllMethods() {        ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);        // 获取当前类和父类的所有公有方法        Method[] methods = programMonkey.getClass().getMethods();        for (Method method : methods) {            LogE("method name : " + method.getName());        }         try {            Method setmLanguageMethod = programMonkey.getClass().getMethod("setmLanguage", String.class);            setmLanguageMethod.setAccessible(true);             // 获取返回类型            Class returnType = setmLanguageMethod.getReturnType();            LogE("setmLanguage 方法的返回类型 : " + returnType.getName());             // 获取方法的参数类型列表            Class[] paramClasses = setmLanguageMethod.getParameterTypes() ;            for (Class class1 : paramClasses) {                LogE("setmLanguage 方法的参数类型 : " + class1.getName());            }             // 是否是 private 函数,属性是否是 private 也可以使用这种方式判断            LogE(setmLanguageMethod.getName() + " is private " + Modifier.isPrivate(setmLanguageMethod.getModifiers()));             // 执行方法            Object result = setmLanguageMethod.invoke(programMonkey, "Java");            LogE("setmLanguage 方法的返回结果: " + result);        } catch (Exception e) {            e.printStackTrace();        }    }     private Class getClassObject_1(){        return ProgramMonkey.class;    }     private Class getClassObject_2(){        ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);        return programMonkey.getClass();    }     private Class getClassObject_3(){        try{            return Class.forName("com.eebbk.reflectdemo.ProgramMonkey");        }catch(ClassNotFoundException e){            e.printStackTrace();        }         return null;    }     /**     * 得到当前类的所有实例     *     * */    private void getCurrentClassFields() {        ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);        // 获取当前类的所有属性        Field[] publicFields = programMonkey.getClass().getDeclaredFields();        for (Field field : publicFields) {            LogE("declared field name : " + field.getName());        }         try {            // 获取当前类的某个属性            Field ageField = programMonkey.getClass().getDeclaredField("mAge");            // 获取属性值            LogE(" my age is : " + ageField.getInt(programMonkey));            // 设置属性值            ageField.set(programMonkey, 10);            LogE(" my age is : " + ageField.getInt(programMonkey));        } catch (Exception e) {            e.printStackTrace();        }    }     /**     * 得到当前类和父类的所有公有属性     *     * */    private void getAllFields() {        ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);        // 得到当前类和父类的所有公有属性        Field[] publicFields = programMonkey.getClass().getFields();        for (Field field : publicFields) {            LogE("field name : " + field.getName());        }         try {            // 获取当前类和父类的某个公有属性            Field ageField = programMonkey.getClass().getField("mAge");            LogE(" age is : " + ageField.getInt(programMonkey));            ageField.set(programMonkey, 8);            LogE(" my age is : " + ageField.getInt(programMonkey));        } catch (Exception e) {            e.printStackTrace();        }    }     private void LogE(String msg){        Log.e("Reflection", "============== " + msg);    }} 演示结果: 三种获取类信息的方式: 获取当前类的方法、获取当前类和父类的所有公有方法: 获取当前类的所有实例、获取当前类和父类的所有公有实例: 获取父类信息: 获取接口信息: 比较反射方法和实例的性能差异: 通过上面的示例可以发现,通过反射能够完成之前所描述的事情,并且反射方法比反射实例要慢很多。 反射的特点 优点 灵活、自由度高: 不受类的访问权限限制,想对类做啥就做啥; 缺点 性能问题: 通过反射访问、修改类的属性和方法时会远慢于直接操作,但性能问题的严重程度取决于在程序中是如何使用反射的。如果使用得很少,不是很频繁,性能将不会是什么问题; 安全性问题: 反射可以随意访问和修改类的所有状态和行为,破坏了类的封装性,如果不熟悉被反射类的实现原理,随意修改可能导致潜在的逻辑问题; 兼容性问题: 因为反射会涉及到直接访问类的方法名和实例名,不同版本的API如果有变动,反射时找不到对应的属性和方法时会报异常; 说明 通过反射访问方法比实例慢很多; 有用到反射的类不能被混淆; 反射存在性能问题,但使用不频繁、按需使用时,对程序性能影响并不大; 反射存在安全性问题,因为可以随意修改类的所有状态和行为(包括private方法和实例); 使用反射访问Android的API时需要注意因为不同API版本导致的兼容性问题;

相关文章