深入浅出谈反射

什么是反射?

反射是一种能够在程序运行时动态访问、修改某个类中任意属性(状态)和方法(行为)的机制(包括private实例和方法),java反射机制提供了以下几个功能:

在运行时判断任意一个对象所属的类;

在运行时构造任意一个类的对象;

在运行时判断任意一个类所具有的成员变量和方法;

在运行时调用任意一个对象的方法。

反射涉及到四个核心类:

java.lang.Class.java:类对象;

java.lang.reflect.Constructor.java:类的构造器对象;

java.lang.reflect.Method.java:类的方法对象;

java.lang.reflect.Field.java:类的属性对象;

反射有什么用?

操作因访问权限限制的属性和方法;

实现自定义注解;

动态加载第三方jar包,解决android开发中方法数不能超过65536个的问题;

按需加载类,节省编译和初始化APK的时间;

反射工作原理

当我们编写完一个Java项目之后,每个java文件都会被编译成一个.class文件,这些Class对象承载了这个类的所有信息,包括父类、接口、构造函数、方法、属性等,这些class文件在程序运行时会被ClassLoader加载到虚拟机中。当一个类被加载以后,Java虚拟机就会在内存中自动产生一个Class对象。我们通过new的形式创建对象实际上就是通过这些Class来创建,只是这个过程对于我们是不透明的而已。

反射的工作原理就是借助Class.java、Constructor.java、Method.java、Field.java这四个类在程序运行时动态访问和修改任何类的行为和状态。

反射实例

分别演示三种获取类信息的方式、获取当前类的所有方法和获取当前类及其父类的所有方法、获取当前类的所有实例和获取当前类及其父类的所有实例、获取父类信息、获取接口信息、比较反射方法和实例的性能差异等几个方面:

示例类:

父类Personon.java:

packagecom.eebbk.reflectdemo;publicclassPerson{    String mName;    String mSex;publicintmAge;publicPerson(String aName, String aSex,intaAge){        mName = aName;        mSex = aSex;        mAge = aAge;    }publicintgetmAge(){returnmAge;    }publicvoidsetmAge(intmAge){this.mAge = mAge;    }publicStringgetmName(){returnmName;    }publicvoidsetmName(String mName){this.mName = mName;    }publicStringgetmSex(){returnmSex;    }publicvoidsetmSex(String mSex){this.mSex = mSex;    }privateStringgetDescription(){return"黄种人";    }}

接口ICompany.java:

packagecom.eebbk.reflectdemo;publicinterfaceICompany{StringgetCompany();}

子类ProgramMonkey.java:

packagecom.eebbk.reflectdemo;publicclassProgramMonkeyextendsPersonimplementsICompany{String mLanguage ="C#";String mCompany ="BBK";publicProgramMonkey(String aName, String aSex,intaAge){super(aName, aSex, aAge);    }publicProgramMonkey(String language, String company, String aName, String aSex,intaAge){super(aName, aSex, aAge);        mLanguage = language;        mCompany = company;    }publicStringgetmLanguage(){returnmLanguage;    }publicvoidsetmLanguage(String mLanguage){this.mLanguage = mLanguage;    }privateintgetSalaryPerMonth(){return12306;    }@OverridepublicStringgetCompany(){returnmCompany;    }}

示例类ReflectActivity.java:

publicclassReflectActivityextendsActivity{@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);        setContentView(R.layout.activity_reflect_layout);    }publicvoidonClick(View v){switch(v.getId()){caseR.id.getClassObjectBtnId:{                getClassObject();            }break;caseR.id.getMethodInfoBtnId:{                getMethodInfo();            }break;caseR.id.getFieldInfoBtnId:{                getFieldInfo();            }break;caseR.id.getSuperClassInfoBtnId:{                getSuperClass();            }break;caseR.id.getInterfaceInfoBtnId:{                getInterfaces();            }break;caseR.id.compareMethodAndFieldBtnId:{                compareCallMethodAndField();            }break;default:{            }break;        }    }privatevoidgetClassObject(){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());    }privatevoidgetMethodInfo(){        getAllMethods();        getCurrentClassMethods();    }privatevoidgetFieldInfo(){        getAllFields();        getCurrentClassFields();    }privatevoidgetSuperClass(){ProgramMonkey programMonkey =newProgramMonkey("小明","男",12);        Class<?> superClass = programMonkey.getClass().getSuperclass();while(superClass !=null) {LogE("programMonkey's super class is : "+ superClass.getName());                        superClass = superClass.getSuperclass();        }    }privatevoidgetInterfaces(){ProgramMonkey programMonkey =newProgramMonkey("小明","男",12);        Class<?>[] interfaceses = programMonkey.getClass().getInterfaces();for(Class class1 : interfaceses) {LogE("programMonkey's interface is : "+ class1.getName());        }    }privatevoidcompareCallMethodAndField(){longcallMethodCostTime = getCallMethodCostTime(10000);LogE("callMethodCostTime == "+ callMethodCostTime);longcallFieldCostTime = getCallFieldCostTime(10000);LogE("callFieldCostTime == "+ callFieldCostTime);    }privatelonggetCallMethodCostTime(intcount){longstartTime = System.currentTimeMillis();for(intindex =0; index < count; index++){ProgramMonkey programMonkey =newProgramMonkey("小明","男",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();            }        }returnSystem.currentTimeMillis()-startTime;    }privatelonggetCallFieldCostTime(intcount){longstartTime = System.currentTimeMillis();for(intindex =0; index < count; index++){ProgramMonkey programMonkey =newProgramMonkey("小明","男",12);try{Field ageField = programMonkey.getClass().getDeclaredField("mLanguage");ageField.set(programMonkey,"Java");}catch(NoSuchFieldException e){                e.printStackTrace();}catch(IllegalAccessException e){                e.printStackTrace();            }        }returnSystem.currentTimeMillis()-startTime;    }    privatevoidgetCurrentClassMethods(){ProgramMonkey programMonkey =newProgramMonkey("小明","男",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());            }            LogE(getSalaryPerMonthMethod.getName() +" is private "+ Modifier.isPrivate(getSalaryPerMonthMethod.getModifiers()));                        Object result = getSalaryPerMonthMethod.invoke(programMonkey);LogE("getSalaryPerMonth 方法的返回结果: "+ result);}catch(Exception e) {            e.printStackTrace();        }    }    privatevoidgetAllMethods(){ProgramMonkey programMonkey =newProgramMonkey("小明","男",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());            }            LogE(setmLanguageMethod.getName() +" is private "+ Modifier.isPrivate(setmLanguageMethod.getModifiers()));            Object result = setmLanguageMethod.invoke(programMonkey,"Java");LogE("setmLanguage 方法的返回结果: "+ result);}catch(Exception e) {            e.printStackTrace();        }    }privateClass getClassObject_1(){returnProgramMonkey.class;    }privateClass getClassObject_2(){ProgramMonkey programMonkey =newProgramMonkey("小明","男",12);returnprogramMonkey.getClass();    }privateClass getClassObject_3(){try{returnClass.forName("com.eebbk.reflectdemo.ProgramMonkey");}catch(ClassNotFoundException e){            e.printStackTrace();        }returnnull;    }    privatevoidgetCurrentClassFields(){ProgramMonkey programMonkey =newProgramMonkey("小明","男",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();        }    }    privatevoidgetAllFields(){ProgramMonkey programMonkey =newProgramMonkey("小明","男",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();        }    }privatevoidLogE(String msg){Log.e("Reflection","============== "+ msg);    }}

演示结果:

三种获取类信息的方式:

获取当前类的方法、获取当前类和父类的所有方法:

获取当前类的所有实例、获取当前类和父类的所有实例:

获取父类信息:

获取接口信息:

比较反射方法和实例的性能差异:

通过上面的示例可以发现,通过反射能够完成之前所描述的事情,并且反射方法比反射实例要慢很多。

反射的特点

优点

灵活、自由度高:不受类的访问权限限制,想对类做啥就做啥;

缺点

性能问题:通过反射访问、修改类的属性和方法时会远慢于直接操作,但性能问题的严重程度取决于在程序中是如何使用反射的。如果使用得很少,不是很频繁,性能将不会是什么问题;

安全性问题:反射可以随意访问和修改类的所有状态和行为,破坏了类的封装性,如果不熟悉被反射类的实现原理,随意修改可能导致潜在的逻辑问题;

兼容性问题:因为反射会涉及到直接访问类的方法名和实例名,不同版本的API如果有变动,反射时找不到对应的属性和方法时会报异常;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农老K

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值