今天小编为年夜家带来的 是java反射教程,对于java反射,年夜家都有很多疑问,今天小编就来为年夜家一一解答。
反射真的 存在机能问题吗
照样应用上篇文章的 demo,为了放年夜问题,找到共性,采取逐渐扩年夜测试次数、每次测试多次取平均值的 方法,针对同一个办法分别就直接调用该办法、反射调用该办法、直接调用该办法对应的 实例、反射调用该办法对应的 实例分别从1-1000000,每隔一个数量级测试一次 测试代码如下(Person、ICompany、ProgramMonkey这三个类已在之前的 文章中贴出) public class ReflectionPerformanceActivity extends Activity{
private TextView mExecuteResultTxtView = null;
private EditText mExecuteCountEditTxt = null;
private Executor mPerformanceExecutor = Executors.newSingleThreadExecutor();
private static final int AVERAGE_COUNT = 10;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_reflection_performance_layout);
mExecuteResultTxtView = (TextView)findViewById(R.id.executeResultTxtId);
mExecuteCountEditTxt = (EditText)findViewById(R.id.executeCountEditTxtId);
}
public void onClick(View v){
switch(v.getId()){
case R.id.executeBtnId:{
execute();
}
break;
default:{
}
break;
}
}
private void execute(){
mExecuteResultTxtView.setText("");
mPerformanceExecutor.execute(new Runnable(){
@Override
public void run(){
long costTime = 0;
int executeCount = Integer.parseInt(mExecuteCountEditTxt.getText().toString());
long reflectMethodCostTime=0,normalMethodCostTime=0,reflectFieldCostTime=0,normalFieldCostTime=0;
updateResultTextView(executeCount + "毫秒耗时情况测试");
for(int index = 0; index < AVERAGE_COUNT; index++){
updateResultTextView("第 " + (index+1) + " 次");
costTime = getNormalCallCostTime(executeCount);
reflectMethodCostTime += costTime;
updateResultTextView("履行直接调用办法耗时" + costTime + " 毫秒");
costTime = getReflectCallMethodCostTime(executeCount);
normalMethodCostTime += costTime;
updateResultTextView("履行反射调用办法耗时" + costTime + " 毫秒");
costTime = getNormalFieldCostTime(executeCount);
reflectFieldCostTime += costTime;
updateResultTextView("履行通俗调用实例耗时" + costTime + " 毫秒");
costTime = getReflectCallFieldCostTime(executeCount);
normalFieldCostTime += costTime;
updateResultTextView("履行反射调用实例耗时" + costTime + " 毫秒");
}
updateResultTextView("履行直接调用办法平均耗时" + reflectMethodCostTime/AVERAGE_COUNT + " 毫秒");
updateResultTextView("履行反射调用办法平均耗时" + normalMethodCostTime/AVERAGE_COUNT + " 毫秒");
updateResultTextView("履行通俗调用实例平均耗时" + reflectFieldCostTime/AVERAGE_COUNT + " 毫秒");
updateResultTextView("履行反射调用实例平均耗时" + normalFieldCostTime/AVERAGE_COUNT + " 毫秒");
}
});
}
private long getReflectCallMethodCostTime(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 getReflectCallFieldCostTime(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 long getNormalCallCostTime(int count){
long startTime = System.currentTimeMillis();
for(int index = 0 ; index < count; index++){
ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);
programMonkey.setmLanguage("Java");
}
return System.currentTimeMillis()-startTime;
}
private long getNormalFieldCostTime(int count){
long startTime = System.currentTimeMillis();
for(int index = 0 ; index < count; index++){
ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);
programMonkey.mLanguage = "Java";
}
return System.currentTimeMillis()-startTime;
}
private void updateResultTextView(final String content){
ReflectionPerformanceActivity.this.runOnUiThread(new Runnable(){
@Override
public void run(){
mExecuteResultTxtView.append(content);
mExecuteResultTxtView.append("\n");
}
});
}} 测试成果如下 反射机能测试成果 测试结论 反射的 确会导致机能问题; 反射导致的 机能问题是否严重跟应用的 次数有关系,假如控制在100次以内,根本上没什么差别,假如调用次数跨越了100次,机能差别会很明显; 四种拜访方法,直接拜访实例的 方法效力最高;其次是直接调用办法的 方法,耗时约为直接调用实例的 1.4倍;接着是经由过程反射拜访实例的 方法,耗时约为直接拜访实例的 3.75倍;最慢的 是经由过程反射拜访办法的 方法,耗时约为直接拜访实例的 6.2倍; 反射到底慢在哪? 跟踪源码可以发明,四个办法中都存在实例化ProgramMonkey的 代码,所以可以清除是这句话导致的 不合调用方法产生的 机能差别;经由过程反射调用办法中调用了setAccessible办法,但该办法纯粹只是设置属性值,不会产生明显的 机能差别;所以最有可能产生机能差别的 只有getMethod和getDeclaredField、invoke和set办法了。 下面分别就这两组办法进行测试,找到具体慢在哪? 起首测试invoke和set办法,修改getReflectCallMethodCostTime和getReflectCallFieldCostTime办法的 代码如下
private long getReflectCallMethodCostTime(int count){
long startTime = System.currentTimeMillis();
ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);
Method setmLanguageMethod = null;
try{
setmLanguageMethod = programMonkey.getClass().getMethod("setmLanguage", String.class);
setmLanguageMethod.setAccessible(true);
}catch(NoSuchMethodException e){
e.printStackTrace();
}
for(int index = 0 ; index < count; index++){
try{
setmLanguageMethod.invoke(programMonkey, "Java");
}catch(IllegalAccessException e){
e.printStackTrace();
}catch(InvocationTargetException e){
e.printStackTrace();
}
}
return System.currentTimeMillis()-startTime;
}
private long getReflectCallFieldCostTime(int count){
long startTime = System.currentTimeMillis();
ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);
Field ageField = null;
try{
ageField = programMonkey.getClass().getDeclaredField("mLanguage");
}catch(NoSuchFieldException e){
e.printStackTrace();
}
for(int index = 0 ; index < count; index++){
try{
ageField.set(programMonkey, "Java");
}catch(IllegalAccessException e){
e.printStackTrace();
}
}
return System.currentTimeMillis()-startTime;
}
Java反射教程沿用上面的 测试办法,测试成果如下 invoke和set 修改getReflectCallMethodCostTime和getReflectCallFieldCostTime办法的 代码如下,对getMethod和getDeclaredField进行测试 private long getReflectCallMethodCostTime(int count){
long startTime = System.currentTimeMillis();
ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);
for(int index = 0 ; index < count; index++){
try{
Method setmLanguageMethod = programMonkey.getClass().getMethod("setmLanguage", String.class);
}catch(NoSuchMethodException e){
e.printStackTrace();
}
}
return System.currentTimeMillis()-startTime;}private long getReflectCallFieldCostTime(int count){
long startTime = System.currentTimeMillis();
ProgramMonkey programMonkey = new ProgramMonkey("小明", "男", 12);
for(int index = 0 ; index < count; index++){
try{
Field ageField = programMonkey.getClass().getDeclaredField("mLanguage");
}catch(NoSuchFieldException e){
e.printStackTrace();
}
}
return System.currentTimeMillis()-startTime;} 沿用上面的 测试办法,测试成果如下 getMethod和getDeclaredField 测试结论 getMethod和getDeclaredField办法会比invoke和set办法耗时; 跟着测试数量级越年夜,机能差别的 比例越趋于稳定; 因为测试的 这四个办法最终调用的 都是native办法,无法进一步跟踪。小我猜测应当是和在法度榜样运行时操作class有关,比如须要断定是否安然?是否许可如许操作?入参是否精确?是否可以或许在虚拟机中找到须要反射的 类?主如果这一系列断定前提导致了反射耗时;也有可能是因为调用natvie办法,须要应用JNI接口,导致了机能问题(参照Log.java、System.out.println,都是调用native办法,反复调用多次耗时很明显)。 假如避免反射导致的 机能问题,广州java培训Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。? 经由过程上面的 测试可以看出,过多地应用反射,的 确会存在机能问题,但假如应用合适,所谓反射导致机能问题也就不是问题了,关于反射对机能的 影响,参照下面的 应用原则,并不会有什么明显的 问题 不要过于频繁地应用反射,年夜量地应用反射会带来机能问题; 经由过程反射直接拜访实例会比拜访办法快很多,所以应当优先采取拜访实例的 方法。 跋文 上面的 测试并不周全,但在必定程度上可以或许反应出反射的 确会导致机能问题,也可以或许年夜概知道是哪个处所导致的 问题。假如后面有须要进一步测试,我会从下面几个方面作进一步测试 测试频繁调用native办法是否会有明显的 机能问题; 测试同一个办法内,过多的 前提断定是否会有明显的 机能问题; 测试类的 复杂程度是否会对反射的 机能有明显影响。 以上就是小编为年夜家带来的 Java反射教程,欲望对年夜家有所赞助。 |